JVM GC垃圾回收机制

学习JVM垃圾回收机制主要学习以下几点:哪些内存需要回收(判断对象可以回收)、什么时候回收(GC什么时候执行)、怎么回收(垃圾回收算法、垃圾回收器)、垃圾回收过程

JVM GC回收哪些区域内的垃圾?

JVM GC只回收堆区和方法区内的对象,不回收虚拟机栈内的数据,栈内数据在超出作用域后会被JVM自动释放掉。

因为JVM GC回收堆区的对象,所以先了解学习一下堆内存的结构图:

堆内存分为年轻代(Young Generation)老年代(Old Generation),年轻代和老年代所占空间比例默认是1:2。年轻代又分为EdenSurvivor区,Survivor区由FormSpaceToSpace组成。Eden区占大容量,Survivor两个区占小容量,默认比例是8:1:1。From和To主要是为了解决内存碎片化。

JVM GC怎么判断对象可以回收?

  • 对象没有引用。
  • 作用域发生未捕获异常。
  • 程序在作用域正常执行完毕。
  • 程序执行了System.exit()
  • 程序发生意外终止(被杀进程等)。

判断对象是否可以回收涉及到垃圾回收算法,后面我们会详情说明。

有些时候我们可以把相关的对象设置成null来试图显示的清除缓存,但是并不是设置null就一定被标记成可以回收,比如以下代码:

public static void testGC() { 
    ReferenceCountingGC objA = new ReferenceCountingGC(); 
    ReferenceCountingGC objB = new ReferenceCountingGC(); 
    objA.instance = objB; 
    objB.instance = objA; 
    objA = null; 
    objB = null; 
    // 假设在这行发生GC, objA和objB是否能被回收? 
    System.gc(); 
}

objAobjB设置null不会被标记成可以回收因为objAobjB循环依赖引用关系,但是System.gc();会执行Full GC回收。

将对象设置null至少没有什么坏处,但是System.gc();便不可取了,因为使用System.gc();的时候并不是马上执行GC操作,而是会等待一段时间,甚至不会执行,如果被执行会触发Full GC是非常影响性能的。

JVM GC什么时候执行?

Eden区空间不够储存对象的时候会执行Minro GC。升到老年代的对象大于老年代剩余的空间时执行Full GC,或者小于的时候被HandlePromotionFailure参数强制Full GC。JVM GC调优主要是减少Full GC的触发次数,可以通过设置参数NewRatio控制年轻代和老年代所占内存比例,通过设置参数MaxTenuringThreshold改变对象进入老年代的阙值。Full GC非常损耗性能,执行时间大概是Minro GC的10倍。

JVM GC按代的垃圾回收机制

年轻代:绝大多数新创建的对象都是被分配在年轻代(对象很大的话可能被分配在老年代),年轻代触发GC对象被回收的过程称之为Minor GC

老年代:对象在年轻代周期存活了下来,会被拷贝到老年代,老年代触发GC对象被回收的过程称之为Full GC

持久代:也被叫做方法区,用于保存类加载信息、常量、静态变量等,方法区不是用于储存老年代存活下来的对象,这个区域也可能发生GC,方法发生GC的过程被称为Major GC,方法区发生GC的条件非常苛刻,必须满足以下三个条件才会回收:

  • 所有实例被回收。
  • 加载该类的ClassLoader被回收。
  • Class对象无法通过任务途径访问(包含反射)。

老年代如何解决引用年轻代对象问题?

老年代中存在一个card table,大小为512字节,用于存放所有老年代对象执行年轻代对象的引用,当针对年轻代执行GC的时候,只需查询一下card table来决定是否回收,而不同查询整个老年代。

垃圾回收过程

  1. 绝大数刚刚新建的对象都会储存在年轻代的Eden区。
  2. 当Eden区空间不足时就会执行GC,在执行第一次GC之后存活的对象就会移动到Survivor的From区。
  3. 此后每次Eden区执行GC,存活的对象都会被存放在From区。
  4. 当From区空间饱和时,在存活的对象就会被移动到to区,然后清空from区。
  5. 在以上步骤重复N次(N=MaxTenuringThreshold 年龄阙值默认15)依然存活的对象就会移到老年代,如果这个时候老年代没有空间了就会触发Full GC,如果触发 Full GC之后空间还是不足就会抛出OOM异常。

JVM GC核心参数

-XX:NewRatio 
–XX:SurvivorRatio 
–XX:NewSize 
–XX:MaxNewSize

-XX:NewRatio表示年轻代和老年代相对的比例,比如-XX:NewRatio=2表示老年代是年轻代的2被,老年代占堆的2/3,年轻代占1/3。

-XX:SurvivorRatio表示年轻代里面Eden区和Survivor区相比比例,比如-XX:SurvivorRatio=8表示Eden:From:To = 8:1:1。SurvivorRatio不能设置过大也不能设置过小,一般默认值即可。

-XX:NewSize表示年轻代的初始化大小。

-XX:MaxNewSize表示年轻代最大大小。

JVM GC算法

根搜索算法

程序把所有引用关系看作一棵树,从一个根节点GC ROOT开始寻找对应的引用节点,找到这个节点后继续寻找这个节点的引用节点,当所有节点寻找完毕之后,没有被引用的节点就是无用的节点。

image

上图红色就是无用的节点,可以被回收。

目前Java中可以作为GC ROOT的对象有:

  • 虚拟机栈、本地方法栈中引用的对象,对象分别是本地变量表、Native对象。
  • 方法区中静态变量、常量引用的对象。

标记-清除算法

image

标记-清除算法采用从根集合进行扫描,对存活的对象进行标记,标记完毕之后再扫描整个空间中未被标记的对象进行回收。

标记-清除算法不需要进行对象的移动,并且仅对不存活的对象进行回收,在存活的对象比较多的情况下极为高效,但是由于标记-清除算法直接回收不存活的对象,没有对还存活的对象进行整理,所以会导致内存碎片化。

复制算法

image

复制算法将内存空间划分为两个区间,所有对象都只会分配在其中一个活动区间,而另外一个区间则是空闲的。

复制算法采用从根集合扫描,将存活的对象复制到空闲区间,当扫描完毕之后,会将活动区间一次性回收,此时原本的空闲区间变成了活动区间,下次GC的时候又重复此操作。复制算法在存活对象比较少的时候极为高效。

标记-整理算法

image

标记-整理算法采用标记-清除算法一样的方式进行对象的标记、回收,但是在回收不存活对象占用的空间后,会将所有存活的对象往左移动,并更新对应的指针,解决了内存碎片的问题。

JVM为了优化内存的回收,使用分代回收的方式,年轻代内存回收采用复制算法,老年代回收大多采用标记-整理算法。

垃圾回收器

年轻代回收器

Serial:

  • 算法:复制算法
  • 说明:简单高效的单核机器,Client模式下默认的年轻代收集器。

ParNew

  • 算法:复制算法
  • 说明:Serial的多线程版本,运行在Server模式下的JVM首选的新生代收集器。

Parallel Scavenge

  • 算法:复制算法
  • 说明:又被称为吞吐量优先收集器,和ParNew 收集器类似,目标在于达到可控制吞吐量。

老年代回收器

Serial Old

  • 算法:标记-整理算法
  • 说明:性能一般,单线程版本,在JDK1.5及之前的版本中与Parallel Scavenge收集器搭配使用,作为CMS收集器的后备预案。

Parallel Old

  • 算法:标记-整理算法
  • 说明:GC多线程并行,为了替代 Serial Old 与 Parallel Scavenge 配合使用。

CMS

  • 算法:标记-清除算法
  • 说明:对CPU资源敏感,停顿时间长。会产生内存碎片,可以通过参数开启碎片的合并整理。 基本已被 G1 取代。

年轻代、老年代共用回收器

G1

  • 算法:标记-整理算法
  • 说明:新的垃圾回收器,既可以回收新生代也可以回收老年代,适用于多核大内存机器、GC多线程并行执行,停顿低、高回收率。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容