JVM之Java内存区域
世界上并没有完美的程序,但我们并不因此而沮丧,因为写程序本来就是一个不断追求完美的过程。
一、JAVA内存区域
谈及JAVA虚拟机运行时数据区域就不得不祭出这张经典的图了:
Java虚拟机在执行Java程序的过程中会把它管理的内存划分为若干个不同的数据区域,包括:
- 线程隔离的数据区
- 所有线程共享的数据区
- 堆
- 方法区
二、对象的创建过程
当Java虚拟机遇到一条new指令时,是如何创建一个对象的?
- 首先根据这个指令的参数在常量池中定位到一个类的引用;
- 检查这个符号引用对应的类是否已经被加载、解析和初始化过?
- 若没有:先执行相对应的类加载过程
- 类加载检查通过后,虚拟机为新生对象在堆中分配内存;
- 将分配到的内存空间(不包括对象头)都初始化为零值,设置对象头(哪个类的实例、如何找到类的元数据信息、对象的哈希码、对象的GC分代年龄等);
- 执行构造函数,即Class文件中的
<init>()
方法,按照程序员的意愿对对象进行初始化,至此一个真正可用的对象才算呗完全构造出来。
存储内容 | 标志位 | 状态 |
---|---|---|
对象哈希码、对象分代年龄 | 01 | 未锁定 |
指向锁记录的指针 | 00 | 轻量级锁定 |
指向重量级锁的指针 | 10 | 膨胀(重量级锁定) |
空,不需要记录信息 | 11 | GC标记 |
偏向线程ID、偏向时间戳、对象分代年龄 | 01 | 可偏向 |
这块内容暂时不理解,待后续完善~
三、对象的访问定位
Java程序会通过栈上的reference数据来操作堆中的具体对象。
对象的主流访问方式主要有两种:使用句柄和直接指针。
- 使用句柄
- Java堆中会划分出一块内存来作为句柄池,reference中存储的就是对象的句柄地址,而句柄中包含了对象的实例数据和类型数据各自具体的地址信息。
- 好处:reference中存储的是稳定的句柄地址,在对象被移动后(GC时移动对象)只会改变句柄中的实例数据指针,而reference本身不需要被修改。
- 直接指针
- Java堆中的对象需要存放访问类型数据的相关信息,而reference存储的直接就是对象地址。
- 好处:速度更快,节省了一次指针定位的时间开销(HotSpot虚拟机主要使用此种方式)。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。