JVM垃圾回收机制

一、如何判断对象已死

1、引用计数算法

给每个对象添加一个引用计数器,每当一个地方引用他时,引用计数器加一,引用失效时,计数减一。这种方法存在问题,即循环引用的问题。

2、可达性算法分析

通过一系列的“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索的路径称为引用链,当一个对象到GC Roots没有任何引用链时,则证明对象不可用。

GC Roots的对象包括以下几种:

(1)虚拟机栈中引用的对象

(2)方法区中静态属性引用的对象

(3)方法区中的常量

(4)本地方法区中Native方法引用的对象

二、垃圾收集算法

1、标记-清除算法

2、复制算法

3、标记-整理算法

4、分代收集算法

三、垃圾收集器

新生代:Serial    ParNew      Parallel Scavenge

老年代:CMS    Serial Old    Parallel Old

包含所有的收集器:G1

1、Serial收集器

单线程收集器 新生代采取复制算法,老年代使用的是标记-整理法

2、ParaNew收集器

实际上是Serial的多线程版本。只有他能与CMS配合工作

3、parallel Scavenge收集器

关注点与其他垃圾收集器不同,其他垃圾收集器尽可能缩短垃圾收集时用户的暂停时间,Parallel Scavenge收集器关注的是可控制的吞吐量。即:

运行时用户代码时间/(用户代码时间+垃圾收集时间)提供两个参数用于精确控制吞吐量:-XX:MaxGCPauseMills(控制最大垃圾收集停顿时间)和-XX:GCTimeRatio(设置吞吐量大小)

4、Serial Old收集器

Serial收集器的老年代版本,使用标记整理法。主要是两大用途,一是配合Parallel Scavenge收集器使用,另一种用途是作为CMS的备选法案,这一部分在CMS中介绍。

5、Parallel Old收集器

Parallel Scavenge的老年代版本

6、CMS收集器(Concurrent Mark Sweep)

运作过程分为四个步骤

(1)初始标记

(2)并发标记

(3)重新标记

(4)并发清除

其中初始标记和重新标记两个步骤依然需要”stop the world“,初始标记仅仅是标记一下GC Roots能关联到的对象,速度很快。并发标记阶段就是进行GC Root Tracing的过程,重新标记是为了修正并发标记期间用户程序继续运作导致的标记产生变动的那一部分对象的标记记录。

缺点:

a:CMS对CPU资源非常敏感,CMS在并发阶段,虽然不会停止用户程序,但是也要占用CPU资源,占用的数量为(CPU数量+3)/4

b:CMS无法处理浮动垃圾。并发清除阶段用户程序还在运行,导致这时产生的垃圾无法被回收只能等下次回收。这也导致另外一个问题:CMS进行垃圾收集的时候需要预留空间,提供给在并发清理过程中用户程序使用。若预留的空间不够,会发生“Concurrent Mode Failure”,这时会用Srevial Old 收集器进行垃圾收集。

c:CMS是基于标记-清除算法的收集器,会产生内存碎片。解决方法,两个参数 -XX:+UseCMSCompactAtFullCollection:FullGC时开启内存碎片整理

-XX:CMSFullGCsBeforeCollection:设置执行多少次不压缩的Full GC后,跟着来一次带压缩的Full GC

7、G1收集器

特点:

(1)并行与并发:缩短用户程序停顿的时间

(2)分代收集:G1不需要其他的垃圾收集器就能管理整个GC堆

(3)空间整合:基于“标记-整理”算法,不会产生内存碎片

(4)可预测的停顿:可以建立可预测的停顿时间模型,能让使用者明确在一个长度为M毫秒的时间段内,消耗在垃圾收集的时间不超过N毫秒。

G1收集器Java堆的内存布局与其他垃圾收集器有很大不同,G1收集器将整个Java对划分为多个大小相等的独立区域(Region),虽然还有新生代和老年代的区分,但是它们都是Region的一部分。

G1能够建立起可预测的停顿模型就与Region有关。G1跟踪各个Region里面的垃圾堆积的价值大小,在后台维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的region.

如何解决垃圾收集判断对象是否还有引用,会导致全表扫描的问题:使用Remember Set,每个Region里面都会有一个与之对应的remember Set,虚拟机发现程序有对R二分册对象类型的数据进行写操作时,会产生一个Write barrier暂时中断写操作,检查reference引用的对象是否处于不同的Region之中(在分代的例子中就检查老年代的对象是否引用了新生代的对象),如果是,就将相关信息记录到被引用对象所属Region的Remember Set中。当进行内存回收时,在GC Roots的枚举范围值中增加Remember set,即可保证不对全堆扫描也不会有遗漏。

G1收集器大概分为以下几个步骤:

(1)初始标记

(2)并发标记

(3)最终标记

(4)筛选回收

G1与CMS有很多相同之处:初始标记阶段只是标记一下GC Roots能直接关联到的对象,并修改TAMS(Next Top at Mark Start),使让下一阶段用户程序运行时,能够在正确可用的Region中创建对象。这个阶段需要停顿线程。并发标记是从GC Roots开始对堆中的对象进行可达性分析,找出存存活对象,耗时较长,但是可以并发执行。最终标记是为了修正上一阶段用户线程运行时导致标记变化的一部分记录。将这部分记录在线程Remember Set Logs里面。然后将Remember Set Logs这部分数据合并到Remember Set中。这段需要停顿线程,但是标记是并行执行的。最后筛选回收,首先对各个Region的回收价值和成本做排序,然后在根据用户期望的停顿时间进行垃圾回收。这个阶段其实是停顿用户线程的。

四、内存分配与回收策略

Java技术体系中所提倡的自动内存管理其实包括两个部分,如何对对象进行内存分配以及如何回收分配给对象的内存,以上讲了如何回收分配给对象的内存,下面讲讲如何给对象进行内存分配。

对象的内存分配,大方向上就是在堆上进行分配,对象主要是分配在新生代的Eden区中,如果启动了本地线程分配缓冲,将优先在TLAB上进行分配。少数情况直接分配在老年代中。

(1)对象优先在Eden区中进行分配,如果Eden区中空间不够,将触发一次young GC

(2)大对象直接分配在老年代中.Java虚拟机提供了一个-XX:PretenureSizeThreshold,令大于这个设置值的对象直接在老年代分配。

(3)长期存活的对象分配在老年代中。可通过-XX:maxTenuringThreshold设置,默认是15

(4)动态对象年龄的判定。如果在survivor空间中相同年龄所有对象的大小的总和大于survivor区的一半,年龄大于等于这个年龄的对象直接进入老年代。


参考文献:《深入理解Java虚拟机》 周志明 著

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

推荐阅读更多精彩内容

  • 如何判定对象为垃圾对象 在堆里面存放着Java世界中几乎所有的对象实例, 垃圾收集器在对堆进行回收前, 第一件事就...
    FantJ阅读 522评论 0 5
  • 1. 前言 网上关于jvm gc的文章有很多,写这篇文章不是有什么新东西要讲,主要原因是工作时也偶尔碰到比如ful...
    aaron1993阅读 1,223评论 0 0
  • 哪些内存需要回收 由于程序计数器、虚拟机栈、本地方法栈的生命周期都跟随线程的生命周期,当线程销毁了,内存也就回收了...
    Samuel_Tom阅读 7,468评论 1 9
  • 我是日记星球269号星宝宝,我正在参加日记星球第十二期蜕变之旅,这是我的第0492篇原创日记。我相信日积月累的力量...
    cf302fb8f796阅读 94评论 0 0
  • 阳光穿越连续阴冷的雾霾, 堆在树下的积雪依然没有消融, 尘土污染了他当初洁白的身体, 厌恶充斥在撇来的目光里。 冰...
    一弯虹阅读 967评论 19 40