大家可以想一下写代码的时候,如果想要保证一个 HashMap 能够被持续使用,可以把它声明成静态变量,这样就不会被垃圾回收器回收掉 。我们把这些正在使用的引用的入口,叫作GC Roots 。
这种使用 tracing 方式寻找存活对象的方法,还有一个好听的名字,叫作可达性分析法 。
概括来讲,GC Roots 包括:
- Java 线程中,当前所有正在被调用的方法的引用类型参数、局部变量、临时值等 。也就是与我们栈帧相关的各种引用;
- 所有当前被加载的 Java 类;
- Java 类的引用类型静态变量;
- 运行时常量池里的引用类型常量(String 或 Class 类型);
- JVM 内部数据结构的一些引用,比如 sun.jvm.hotspot.memory.Universe 类;
- 用于同步的监控对象,比如调用了对象的 wait() 方法;
- JNI handles,包括 global handles 和 local handles 。
强、软、弱、虚引用那么,通过 GC Roots 能够追溯到的对象,就一定不会被垃圾回收吗?这要看情况 。
Java 对象与对象之间的引用,存在着四种不同的引用级别,强度从高到低依次是:强引用、软引用、弱引用、虚引用 。
- 强应用 默认的对象关系是强引用,也就是我们默认的对象创建方式 。这种引用属于最普通最强硬的一种存在,只有在和 GC Roots 断绝关系时,才会被消灭掉 。
- 软引用 用于维护一些可有可无的对象 。在内存足够的时候,软引用对象不会被回收;只有在内存不足时,系统则会回收软引用对象;如果回收了软引用对象之后,仍然没有足够的内存,才会抛出内存溢出异常 。
- 弱引用 级别就更低一些,当 JVM 进行垃圾回收时,无论内存是否充足,都会回收被弱引用关联的对象 。软引用和弱引用在堆内缓存系统中使用非常频繁,可以在内存紧张时优先被回收掉 。
- 虚引用 是一种形同虚设的引用,在现实场景中用得不是很多 。这里有一个冷门的知识点:Java 9.0 以后新加入了 Cleaner 类,用来替代 Object 类的 finalizer 方法,这就是虚引用的一种应用场景 。
一般情况下,JVM 在做这些事情的时候,都会停止业务线程的所有工作,进入 SafePoint 状态,这也就是我们通常说的 Stop the World 。所以,现在的垃圾回收器,有一个主要目标,就是减少 STW 的时间 。
其中一种有效的方式,就是采用分代垃圾回收,减少单次回收区域的大小 。这是因为,大部分对象,可以分为两类:
- 大部分对象的生命周期都很短
- 其他对象则很可能会存活很长时间
如下图,分代垃圾回收器会在逻辑上,把堆空间分为两部分:年轻代(Young generation)和老年代(Old generation) 。
文章插图
1.年轻代年轻代中又分为一个伊甸园空间(Eden),两个幸存者空间(Survivor) 。对象会首先在年轻代中的 Eden 区进行分配,当 Eden 区分配满的时候,就会触发年轻代的 GC 。
此时,存活的对象会被移动到其中一个 Survivor 分区(以下简称 from);年轻代再次发生垃圾回收,存活对象,包括 from 区中的存活对象,会被移动到 to 区 。所以,from 和 to 两个区域,总有一个是空的 。
Eden、from、to 的默认比例是 8:1:1,所以只会造成 10% 的空间浪费 。这个比例,是由参数 -XX:SurvivorRatio 进行配置的(默认为 8) 。
2.老年代对垃圾回收的优化,就是要让对象尽快在年轻代就回收掉,减少到老年代的对象 。那么对象是如何进入老年代的呢?它主要有以下四种方式 。
- 正常提升(Promotion)
推荐阅读
- 大一新生入学必备清单 上大学要带什么东西
- |混职场必备的五句防身“黑话”,你真正懂得几句,不来了解一下?
- 工作室|梦幻西游:抢资材必备的姿势,新旧两版来回切换,资材量能翻倍
- 鸡胸肉|减脂必备主食:瘦身菜团子,口感鲜香,饱腹感强,好吃不长胖
- 初一女生开学必备物品清单 开学必备物品清单女生
- 中学|县城中学招语文老师,“一个必备条件”让人意外,普通人达不到
- 三角形斜边长度怎么算必备计算公式 直角三角形斜边怎么算
- 韩国旅游必备地图APP 综合评测 韩国旅游地图
- 家电选购全攻略 家电选购必备指南
- 森林燃气灶必备品牌荣誉