垃圾回收机制的各种疑问

jvm的内存模型中,运行时数据区分为哪几个部分?

jvm内存模型

JVM如何判断一个对象所占内存是可以被回收的?

把一系列称为 “GC Roots” 的引用(很多博客说GC Root是对象,严格来讲是对象的引用,并不是对象本身,包括下面列举的四种,也是引用。但是大家都说成对象,也不纠结这些了。)作为起始点,从这些起始点向下搜索,搜索走过的路径就是引用链,当一个对象到 GC Roots 没有任何引用链相连,也就是从 GC Roots 到这个对象不可达时,这个对象可以被回收。

GCRoot包括:

  1. 虚拟机栈(栈帧中的本地变量表)中的引用
  2. 本地方法栈中 JNI(即一般说的 Native 方法)引用
  3. 方法区中类静态属性的引用
  4. 方法区中常量引用

通俗的讲:
1. 虚拟机栈(栈帧中的本地变量表)中引用,是指main函数内新建的局部变量。
2. 本地方法栈中 JNI(即一般说的 Native 方法)引用,JNI核心方法内新建的局部变量。
3. 方法区中类静态属性引用的对象,是指所有的类变量(类的static成员变量)引用。
4. 方法区中常量引用的对象,是指所有的常量(static final)引用。

JVM中如何判断对象可以被回收?
GC Roots 是什么?哪些对象可以作为 GC Root?看完秒懂!

什么是年轻代?

  • 堆内存分为年轻代(Young Generation)、老年代(Old Generation),比例为1:2。年轻代又分为Eden和Survivor区。Survivor区由FromSpace和ToSpace组成。Eden区占大容量,Survivor两个区占小容量,默认比例是8:1:1。。
  • 永久代(Permanent Generation)是方法区的实现,存储程序运行时长期存活的对象,比如类的元数据、方法、常量、属性等。

JVM堆内存(heap)详解

方法区和永久带的联系是什么?

方法区和永久代的关系很像Java中接口和类的关系,类实现了接口,而永久代就是HotSpot虚拟机对虚拟机规范中方法区的一种实现方式。
Java方法区和永久代

为什么要分年轻代和老年代?

  • 新生代(Young Gen):年轻代主要存放新创建的对象,内存大小相对会比较小,垃圾回收会比较频繁。年轻代分成1个Eden Space和2个Suvivor Space(from 和to)。
  • 老年代(Tenured Gen):老年代主要存放JVM认为生命周期比较长的对象(经过15次的Young Gen的垃圾回收后仍然存在),这些对象内存大小相对会比较大,还有大对象,老年代的垃圾回收也相对没有那么频繁。

为什么新生代和老年代要采用不同的回收算法?

  • 在新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就许选择“标记-复制”算法,只需要复制少量存活对象,就可以完成收集。
  • 老年代中因为对象存活率高、没有额外空间对它进行分配担保,就必须使用“标记–清除”、“标记整理”算法来进行回收。如果在老年代采用标记复制算法,需要复制的对象很多,效率不高。

为什么新生代要分出Survivor区?

  • Survivor的存在意义,就是减少被送到老年代的对象,进而减少Full GC的发生。Survivor的预筛选保证,除了大对象(超过Survivor一半)和累加超过Survivor一半的对象之外,其他对象如果在新生代中经历16次Minor GC还能存活,才会被送到老年代。
    详见 为什么新生代内存需要有两个Survivor区?

为什么有两个Survivor区?

  • 两个Survivor区可以减少复制次数,提高效率。

    • 年轻代采用复制算法,如果年轻代只有Eden区和from区,恰好Eden区和From区都存在需要回收的垃圾对象,Eden区的存活对象可以复制到from区对象的后面,然后把Eden区清空。但是From区有垃圾对象也有存活对象,from区的这些对象又往哪里复制?
      1. 如果往老年代复制,老年代也会快速装满,引发full GC,性能降低。
      2. 如果往清空后的Eden区复制, 比如:Eden区ABCDEF对象中,AB存活,From区XYZ对象,X存活。先把AB复制到From区,把Eden区清空,然后再把ABX复制到Eden区,From区清空,From区本身比较小,能装的对象不多,还需要把Eden区的ABX再复制回来。这样做也不是不行,只是相对于from+to机制来说,AB对象多了两次次复制,效率明显低了。再from+to机制下,Eden和from区的存活对象直接复制到to区,然后清空Eden和from区,并且交换from和to 。
  • 另外一篇文章:为什么新生代内存需要有两个Survivor区,给出的观点是两个Survivor区是为了解决碎片化问题,这个观点本人不大认可,但是文章还是值得读的。 因为复制算法本身已经解决了碎片问题,上面的思路2就是例证,只是效率低。所以还是这样做的效率更高。

    聊聊JVM的年轻代
    为什么新生代内存需要有两个Survivor区
    为什么新生代内存需要有两个Survivor区?(腾讯云)

MinorGC和Full GC的区别是什么?

  • MinorGC也称作Young GC,只对Young Gen进行回收。Eden区内存不足时会触发Minor GC。

  • Full GC对年轻代、老年代都进行内存回收。Full GC的触发条件是:

    1. 调用System.gc()只是建议虚拟机执行 Full GC,但是虚拟机不一定真正去执行。
    2. 未指定老年代和新生代大小,堆伸缩时会产生fullgc。
    3. 老年代空间不足。
    4. JDK 1.7 及以前的(永久代)空间满。
    5. 空间分配担保失败。

    Full GC 和 Minor GC,傻傻分不清楚
    一文搞懂Y-GC和Full GC的触发条件
    什么时候会触发Full GC

Java堆内存的新生代Survivor区“To”被填满了,to区中的有的对象年龄还没被复制15次,也会被移动到年老代中吗?

  • 虚拟机并不是永远地要求对象的年龄必须达到了MaxTenuringThreshold才能晋升老年代,如果在Survivor空间中具有相同年龄N的所有对象,如果它们内存大小的总和大于Survivor空间的一半,年龄大于或等于m的对象就可以直接进入老年代,无须等到MaxTenuringThreshold中要求的年龄。


    例如:下面的场景

    MaxTenuringThreshold为15
    年龄1的对象占用了33%
    年龄2的对象占用33%
    年龄3的对象占用34%。

    年龄1的占用了33%,年龄2的占用了33%,累加和超过默认的TargetSurvivorRatio(50%),年龄2和年龄3的对象都要晋升。

    jvm误区–动态对象年龄判定

方法区可以GC吗?

根据Java虚拟机规范的规定,方法区无法满足内存分配需求时,也会抛出OutOfMemoryError异常,虽然规范规定虚拟机可以不实现垃圾收集,因为和堆的垃圾回收效率相比,方法区的回收效率实在太低,但是此部分内存区域也是可以被回收的。
方法区的垃圾回收主要有两种,分别是对废弃常量的回收(常量池的回收)和对无用类的回收(类的卸载)。
JVM:方法区可以GC吗?

垃圾回收会造成,界面卡顿。

详解Java的垃圾回收机制(GC)
Java虚拟机垃圾回收(三) 7种垃圾收集器
Java虚拟机(JVM)你只要看这一篇就够了!
300赞:浅析JAVA的垃圾回收机制(GC)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhangjin1120

可靠的文章费时费力,希望支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值