1.程序指示器
线程私有,当前线程字节码文件执行的行数
2.虚拟机栈
线程私有,生命周期和线程相同,描述的是java方法执行的内存模型:每个方法执行时都会创建一个栈帧,用户存储局部变量、操作数栈、动态链接、方法出口等信息。每个方法的执行到执行完成,对应着一个栈帧从入栈到出栈的过程。如果线程请求的栈的深度大于虚拟机所允许的深度,将抛出SOF,stackOverflowError,如果栈扩展是无法申请到足够的空间,抛出OOM
3.本地方法栈
同虚拟机栈,不过它是为Native方法服务。
4.java堆
线程共享,java堆的唯一目的是存储实例对象,GC的主要是这部分内存,还可以细分新生代、老年代,当然还能再细分,不过不管怎么细分,存储的依然是对象实例。如果堆没有内存完成实例分配,并且堆也无法扩展时,会跑出OOM异常;
5.方法区
线程共享,主要存储已被加载的类信息、静态变量、常亮、及时编译后的代码等。也会抛出OOM。
6.运行是常量池
方法区的一部分,Class文件中除了有类的字段、方法、接口、版本等描述信息外,还有常量池,用于存放编译期生成的各种字面量的和符号引用,这部分信息将在类加载完成后进入运行时常量池。
对象的创建过程
1.首先检查 这个执行的参数能否在常量池中定位到一个类的符号引用,并检查这个符号引用代表的类是否已被加载、验证、初始化,如果没有,则需要先加载类; 2.类加载完成之后,开始进行内存分配,需要分配的内存,在类加载之后就已经确定了,包括指针碰撞和空闲列表两种方法,主要是根据内存是否连续,分配内存的过程中可能遇到并发问题,jvm是通过cas操作保证原子性; 3.类加载完成后,会对类进行初始化为0,不包括对象头,这保证了对象实例字段在java中不需要初始化就能使用。 4.接下来要对对象进行设置,例如:这个对象是哪个类的实例、如果找到类的元数据信息、对象的哈希码、对象的GC分代年龄
对象包含:对象头、实例数据、对齐填充8字节倍数
对象的访问
java程序需要通过java栈本地变量表中的reference数据来操作堆上的具体对象。目前主流的访问方式有句柄和直接指针; 句柄:java堆中分配一块内存作为句柄池,reference中存放的就是对象的句柄地址,句柄中包含了对象的实例数据与数据类型的引用。
直接指针:reference中存放的就是对象的地址,通过对象头中的类型指针,到方法区中找到对象类型数据。