JAVA 运行数据区域
程序计数器
一块较小的内存空间,可以当做当前线程所执行的行号指示器,因为处理器在一个确定是时刻只会执行一个线程中的指令,线程切换后,是通过计数器来记录执行痕迹的,因而可以看出,程序计数器是每个线程私有的。
Java 虚拟机栈
与程序计数器一样,Java 虚拟机栈也是线程私有的。每个方法执行的时候都会创建一个栈帧用于储存局部变量表、操作数栈、动态链接、方法出口等信息。方法调用到结束就对应一个栈帧的入栈到出栈。
局部变量表保存了编译器可以运行的各种基本数据类型,还包括了对象的引用。
如果线程请求栈深度超过虚拟机所允许的深度就会抛出 StackOverflowError 异常。
如果线程请求拓展无法申请到足够的内存就会抛出 OutOfMemoryError 异常。
本地方法栈
本地方法栈与 Java 虚拟机栈的作用很类似,虚拟机栈为虚拟机执行 Java 方法,本地方法栈为虚拟机使用的 Native 方法服务
Java 堆
new 出来的对象实例都会保存在 Java 堆中,这是虚拟机中管理内存中最大的一块了,与前面不同,Java 堆是各个线程的共享区域
方法区
与 Java 堆一样是各个线程的共享区域。
作用是用于储存已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据
运行时常量池
这是方法区的一部分,Class 文件中除了有类的版本、字段、方法、接口等描述信息外还有一项信息是常量池,用于存放编译器生成的各种字面量和符号引用,这部分内容将在类加载后进入方法去的运行时常量池中存放。
直接内存
直接内存不是运行时区域的一部分,但是这部分也被频繁使用。
对象创建过程
在代码级上使用 new
关键字首先会去检查指令参数是否能在常量池中定位到一个类的符号引用,并且检查个符号引用代表的类是否已被加载、解析和初始化过。
检查过后虚拟机就会对新生对象进行分配内存,对象所需大小在类加载之后就能完全确定,然后在 Java 堆中划分出一块足够容纳这个对象的区域。
内存分配完毕之后,虚拟机将分配的内存空间都初始化为零值。
接下来虚拟机对对象进行必要的设置,例如这个对象是哪个类的实例、如何才能找到类的元数据信息、对象的哈希码、对象的 GC 分代年龄等信息。这些信息都保存在对象的对象头之中。
以上工作完成之后,对象创建的 方法还没有执行,所有字段还为零。
执行 方法之后这样才能算真正可用的对象才算完全产生出来。