JVM对象创建与内存分配机制分析
前言
最新的 Java 面试题,技术栈涉及 Java 基础、集合、多线程、Mysql、分布式、Spring全家桶、MyBatis、Dubbo、缓存、消息队列、Linux...等等,会持续更新。
如果对老铁有帮助,帮忙免费点个赞,谢谢你的发财手!
一、对象的创建
- 主要流程:
- 类加载:
JVM执行new指令时,会检查这个类是否已经被加载过了,如果有,则直接返回该对象;
如果没有,那就执行相应的类加载过程。
二、分配内存
-
JVM虚拟机给新生对象分配内存,等同于把一块确定大小的内存从堆中划分出来。
1)内存划分
因为存在内存碎片,JVM会维护一个列表,来记录哪些内存是可用的,在分配的时候从列表中找到一块足够大的空间分配给对象实例,并更新列表上的记录。
2)本地线程分配缓冲
在并发情况下,可能出现正在给对象A分配内存,指针还没来得及修改,对象B又同时使用了原来的指针来分配内存的问题:
解决并发问题的方法:CAS(compare and swap)
虚拟机采用CAS配上失败重试的方式保证更新操作的原子性来对分配内存空间的动作进行同步处理。
三、初始化
- 内存分配完成后,虚拟机需要将分配到的内存空间都初始化为零值(不包括对象头)。
- 这一步操作保证了对象的实例字段在Java代码中可以不赋初始值就直接使用,程序能访问到这些字段的数据类型所对应的零值,比如 int是0,boolean是false。
四、设置对象头
- 在HotSpot虚拟机中,对象在内存中存储的布局可以分为3块区域:对象头(Header)、 实例数据(Instance Data)和对齐填充(Padding)。
HotSpot虚拟机的对象头包括两部分信息, - 第一部分用于存储对象自身的运行时数据, 如哈希码(HashCode)、GC年龄、锁状态标志、线程持有的锁、偏向线程ID等。
- 另外一部分是类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。
五、执行< init>方法
- 执行< init>方法,为属性赋值和执行构造方法。
这里赋值是由程序员赋的值)
六、对象内存分配
Java中的对象都是在堆上进行分配,当对象没有被引用的时候,需要依靠GC进行内存回收。
- 1、新对象都是分配在年轻代中的Eden区(伊甸园区),当Eden区内存不够时,就会触发一次Young GC,把剩余存活的对象都复制到Survivor区(幸存区),同时对象的GC年龄+1;
- 2、如果GC年龄到达15,就会把该对象复制到老年代中;
- 3、如果老年代内存不够时,就会触发一次Full GC,对老年代和年轻代都进行垃圾回收,如果回收完还是没有足够空间存放新的对象,就会发生"OOM"。
如果是需要大量连续内存空间的大对象(比如:字符串、数组),就会直接进入老年代。为了避免复制大对象操作而降低GC性能。
七、对象内存回收
可达性分析算法:
- 将"GC Roots" 对象作为起点,从这些节点开始向下搜索引用的对象,找到的对象都标记为非垃圾对象,其余未标记的
对象都是垃圾对象。 - GC Roots根节点:线程栈的本地变量、静态变量、本地方法栈的变量等。
总结
都已经看到这里啦,赶紧收藏起来,祝您工作顺心,生活愉快!