我爱编程

Java内存区域总结

2017-12-27  本文已影响0人  panning

目录:

一、Java 运行时数据区域
1、程序计数器
2、Java 虚拟机栈
3、本地方法栈
4、Java 堆
5、方法区
二、Java 虚拟机对象的探秘
1、对象的创建
2、对象的内存布局
3、对象的访问定位

一、Java 运行时数据区域

Java 虚拟机在执行 Java 程序的过程中会把所管理的内存划分为若干个不同的数据区域。这些区域都有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有些区域则依赖用户线程的启动和结束而建立和销毁。

根据《Java 虚拟机规范(Java SE 7 版)》的规定,Java 虚拟机所管理的内存将会包括以下几个运行时数据区域(图片来自网络)。 Java虚拟机运行时数据区
1、程序计数器

①、什么是程序计数器

②、程序计数器的作用

③、程序计数器的特性

2、Java 虚拟机栈

与程序计数器一样,Java 虚拟机也是线程私有的,它的生命周期和线程相同。虚拟机栈描述的是 Java 方法执行的内存模型:每个方法在执行的时候都会创建一个栈帧用于存储局部变量表操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。

①、栈帧中局部变量表的作用

②、Java 虚拟机栈的两种异常

3、本地方法栈

虚拟机栈和本地方法栈的区别?虚拟机栈为虚拟机执行 Java 方法(也就是字节码)服务,而本地方法栈则为虚拟机使用到的 Native 方法服务。与虚拟机一样,本地方法区也会抛出 StackOverflowError 和OutOfMemoryError 异常。

4、Java 堆

①、Java堆是Java虚拟机所管理的内存中最大的一块。
②、在虚拟机启动时创建。
③、Java堆内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存(对象实例和数组)
④、如果在堆中没有内存完成实例分配,并且堆也无法再扩展,将会抛出 OutOfMemoryError 异常。

5、方法区

①、方法区的作用:

②、方法区中运行时常量池的作用:

二、Java 虚拟机对象的探秘

介绍完 Java 虚拟机的运行时数据区之后,我们大致知道了虚拟机内存的概况,我们了解了内存中放了些什么后,也许就会想更进一步了解这些虚拟机内存中的数据的其他细节,譬如它们是如何创建的、如何布局的以及如何访问的。对于这样设计细节的问题,必须讨论一下具体的虚拟机和集中在某一个内存区域上才有意义。基于实用优先的原则,这里以常用的内存区域 Java 堆为例,深入探讨 HotSpot 虚拟机在 Java 堆中堆想分配、布局和访问的过程。

1、对象的创建

Java 是一门面向对象的编程语言,在 Java 程序运行过程中无时无刻都有对象被创建出来。在语言层面上,创建对象(例如克隆、反序列化)通常仅仅是一个 new 关键字而已,而在虚拟机中,对象(这里讨论的对象限于普通对象,不包括数组和 Class 对象等)的创建又是怎样一个过程呢?

对象创建的过程如下:
1、虚拟机遇到一个 new 指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已经被加载、解析和初始化过。如果没有,那必须先执行相应的类加载过程。
2、在类加载检查通过后,接下来虚拟机将为新生对象分配内存。
3、内存分配完成之后,虚拟机需要将分配到的内存空间都初始化零值(不包括对象头)。这一步操作保证了对象的 实例字段 在 Java 代码中可以不赋初始值就直接使用,程序能访问到这些字段的数据类型所对象的零值。
4、接下来,虚拟机要对对象进行必要的设置,例如这个对象是哪个类的实例、如何才能找到类的元数据信息、对象的哈希码、对象的 GC 分代年龄信息。这些信息存放在对象的对象头之中。根据虚拟机当前的运行状态的不同,如是否启用偏向锁等,对象头会有不同的设置方式。关于对象头的具体内容,将在下面讲解。
5、在上面的工作都完成之后,从虚拟机的视角来看,一个新的对象已经产生了,但从 Java 程序的视角来看,对象的创建才刚刚开始 —— <init> 方法还没有执行,所有的字段都还为零值。所以,一般来说,执行 new 指令之后会接着执行 <init> 方法,把对象按照码农的意愿进行初始化,这样一个真正可用的对象才算完成产生出来。

2、对象的内存分配

在 HotSpot 虚拟机中,对象在内存中存储的布局可以分为 3 块区域:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)。

①、HotSpot 虚拟机的 对象头 包括两部分信息:

②、实例数据存储布局

③、对齐填充存储布局

3、对象的方位定位

建立对象就是为了使用对象,我们的 Java 程序需要通过栈上的 reference 数据使用堆上的具体对象。由于 reference 类型在 Java 虚拟机规范中规定了一个指向对象的引用,并没有定义这个引用应该通过何种方式去定位、访问堆中的对象的具体位置,所以对象访问方式也是取决于虚拟机实现而定的。

①、目前主流的访问方式有使用 句柄直接指针 两种。

②、两种对象访问方式的优势

最后,需要说明的是,该文章主要是对《深入理解 Java 虚拟机》一书中讲到的 Java 内存区域模块的总结,如有不妥之处,拍砖请轻拍。

上一篇 下一篇

猜你喜欢

热点阅读