jvm运行时内存区域分为:
- 方法区:线程共享,主要用来存储类信息、常量、静态变量、即时编译代码。
- 运行时常量池:属于方法区的一部分,主要存储编译器生成的各种字面量和符号引用
- 字面量:指常量,如:文本字符串,声明为final的常量值等
- 符号引用:类和接口的全限定名、字段名称和描述符、方法的名称和描述符
- 虚拟机栈:线程私有,用来描述方法的执行内存模型,主要存储局部变量表、操作数栈、动态链接以及方法出口。通常我们所说的栈便是指虚拟机栈中局部变量表的部分。
-
局部变量表:存放了编译器可知的各种基本数据类型boolean、byte、char、short、int、float、long、double和reference(对象引用)类型
- 本地方法栈:和虚拟机栈一样只是它针对的是本地方法。
- 堆:线程共享,主要是对象实例分配内存的地方。堆是垃圾收集器管理的主要区域,所以根据垃圾收集器基本都采用的分代收集算法堆可以细分为新生代:Eden空间、From Survivor空间、To Survivor空间和老年代。
- 程序计数器:记录程序执行的行数。
对象的创建、内存布局、访问:
- 对象的创建:
- 当虚拟机遇到一条new指令时,首先会检查这个指令的参数能否在常量池中定位到一个类的符号引用,并检查这个符号引用代表的类是否已经被加载、解析、初始化过。如果没有,则需要先执行相应的类加载过程。
- 分配内存,对象所需的内存大小在类加载完成后便可以完全确定。根据堆中内存是否绝对规整,分别采用指针碰撞和空白列表等方式分配内存。其中对内存分配时的并发安全性可以使用本地分配缓冲(TLAB)的机制来提高内存分配效率。
- 将分配到的内存空间都初始化为零值,对对象头信息进行必要的设置如:该对象是哪个类的实例、如何才能找到类的元数据信息、对象的哈希码、对象的GC分代年龄等信息。
- 对象的内存布局:
- 对象头:分两部份,第一份用于存储对象的运行时数据如:hash码、GC分代年龄、锁状态标志等。第二部份用于存储类型指针
- 实例数据:代码中定义的各种类型字段内容,包括在在父类中定义的字段。
- 对齐填充:这一部分数据没有特别的含义,它仅仅起着占位符的作用,因为HotSpot VM的自动内存管理系统要求对象起始地址必须是8字节的整数倍。
- 对象的访问定位:通过栈上的reference数据来操作堆上的具体对象。通常使用句柄或直接指针访问。