JVM垃圾回收GC算法

一. 什么叫做垃圾回收

垃圾回收(Garbage Collection, GC)
简单来说,就是把不在使用的对象清除掉,释放内存。给其他新生儿腾地方。
Java会对内存进行自动分配与回收管理,使上层业务更加安全,方便地使用内存实现程序逻辑
在不同的JVM实现及不同的回收机制中,堆内存的划分方式是不一样的

二.静态/动态内存分配与回收

正所谓不了解内存的分配与回收不足以了解java堆内存的回收

2.1静态内存分配和回收

定义: 在程序开始运行时由编译器分配的内存
在被编译时就已经能够确定需要的空间,当程序被加载时系统把内存一次性分配给它,这些内存不会在程序执行时发生变化,直到程序执行结束时才回收内存.

  • 包括原生数据类型及对象的引用

  • 这些静态内存空间在栈上分配,方法运行结束,对应的栈帧撤销,内存空间被回收.

  • 每个栈帧中的本地变量表都是在类被加载的时候就确定的,每一个栈帧中分配多少内存,基本上是在类结构确定时就已知了,因此这几块区域内存分配和回收都具备确定性,就不需要过多考虑回收问题了

2.2动态内存分配和回收

在程序执行时才知道要分配的存储空间大小,对象何时被回收也是不确定的,只有等到该对象不再使用才会被回收.

堆和方法区的内存回收具有不确定性,因此垃圾收集器在回收堆和方法区内存的时候花了一点心思.

三.java堆内存回收

3.1 如何判断对象要被回收呢?

GC是如何判断对象是否可以被回收的呢?
为了判断对象是否存活,JVM引入了GC Roots
如果一个对象与GC Roots之间没有直接或间接的引用关系,比如某个失去任何引用的对象,或者两个互相环岛状循环引用的对象等,判决这些对象“死缓”,是可以被回收的

再回收之前要做的一件事情就是,判断哪些是无效对象(一个对象不被任何对象或变量引用)
判断方式有以下2种方式:

  • 引用计数法 (Reference Counting) 每个对象都有一个整型的计数器,当这个对象被一个变量或对象引用时,该计数器加一;当该引用失效时,计数器值减一.当计数器为0时,就认为该对象是无效对象.

  • 可达性分析法 (Reachability Analysis) 所有和GC Roots直接或间接关联的对象都是有效对象,和GC Roots没有关联的对象就是无效对象.说白了点就是和GC Roots有关系,你就是有效的,没关系,那么对不起你就是个无效的,我就要收拾你


两者对比
引用计数法虽然简单,但存在无法解决对象之间相互循环引用的严重问题,且伴随加减法操作的性能影响.
因此,目前主流语言均使用可达性分析方法来判断对象是否有效.


此处应该做下GC Roots的解释,上菜~

GC Roots

  • 虚拟机栈(栈帧中的本地变量表)中引用的对象
  • 方法区中静态属性引用的对象
  • 方法区中常量引用的对象
  • 本地方法栈JNI(native方法)引用的对象

GC Roots并不包括堆中对象所引用的对象!这样就不会出现循环引用.

四.无效对象回收-过程

聊完了什么样的对象会被回收,该聊聊回收的过程是怎么样的了
刚刚说了2种判断方式,那么java采用的是可达性分析法,对于用可达性分析法筛选出来的无效对象,并不是立即清除的,而是给了他一次改过自新的机会

在JVM的垃圾回收器来看。堆区中的每个对象都肯能处于以下三个状态之一:

可触及状态:当一个对象被创建后,只要程序中还有引用变量引用该对象,那么它就始终处于可触及状态。

可复活状态:当程序不再有任何引用变量引用对象时,它就进入可复活状态。该状态的对象,垃圾回收器会准备释放它占用的内存,在释放前,会调用它的finalize()方法,这些finalize()方法有可能使对象重新转到可触及状态。

不可触及状态:当JVM执行完所有的可复活状态的finalize()方法后,假如这些方法都没有使对象转到可触及状态。那么该对象就进入不可触及状态。只有当对象处于不可触及状态时,垃圾回收器才会真正回收它占用的内存

垃圾回收的时间

当一个对象处于可复活状态时,垃圾回收线程执行它的finalize()方法,任何使它转到不可触及状态,任何回收它占用的内存,这对于程序来说都是透明的。程序只能决定一个对象任何不再被任何引用变量引用,使得它成为可以被回收的垃圾。

五.垃圾回收算法

5.1 标记 - 清除

  1. 标记需要回收的内存
  2. 将上述标记的对象进行统一回收


    image.png

劣势

  1. 执行效率不稳定:
    从上述也看出来,这种算法是分2步的,先标记后清除,假如对于有大量对象要回收时,该算法会随着对象的增加效率降低

2.内存碎片化:
从图片中可以看到,当对象被回收后,未使用的区域呈现无规则随机分布,那么伴随而来的就是内存碎片化。同时当有大对象要实例化时,由于内存碎片严重无法分配连续大内存空间,就会在一次导致垃圾回收。

5.2 标记 - 整理

由于标记 - 清除方式会造成内存碎片,继而提出了另一种算法 -- 标记 - 整理
大概意思为:
1.标记需要回收的对象

  1. 将存活的对象向空间内存的一段移动【此时界限就很明确了,同时内存是连续的】
  2. 清理掉无效标记对象


    image.png

劣势
标记整理算法,在老年代区域中每次回收都有大量的对象存活,并且移动对象时需要更新所有对象的引用,所以会造成比较大的系统开销,而且对象移动操作必须全程暂停用户应用程序(Stop The Word)才能进行。

5.3 复制算法

为了能够并行地标记和整理将空间分为两块,每次只激活其中一块,垃圾回收时只需把存活的对象复制到另一块未激活空间上,将未激活空间标记为已激活,将已激活空间标记为未激活,然后清除原空间中的原对象

将内存分成大小相等两份,只将数据存储在其中一块上
1.当需要回收时,首先标记废弃数据

  1. 然后将有用数据复制到另一块内存

  2. 最后将第一块内存空间全部清除


    image.png

劣势

  1. 将内存分为2部分后,内存空间减少,空间利用率缩减
  2. 如果对象存活太多,复制过程中大量存活对象的复制会造成效率低下,开销大;相反,存活对象较少,不失为一种very good的算法

对于以上2点,其实该算法做了比较完善的优化的

优化

堆内存空间分为较大的Eden两块较小的Survivor,每次只使用Eden和Survivor区的一块。这种情形下的“ Mark-Copy"减少了内存空间的浪费。“Mark-Copy”现作为主流的YGC算法进行新生代的垃圾回收。
在新生代中,由于大量对象都是"朝生夕死",也就是一次垃圾收集后只有少量对象存活
因此我们可以将内存划分成三块

  • Eden、Survior1、Survior2
  • 内存大小: Eden : Survior : Survior2 = 8:1:1

分配内存时,只使用Eden和一块Survior1.

  • 当发现Eden+Survior1的内存即将满时,JVM会发起一次Minor GC,清除掉废弃的对象,
  • 并将所有存活下来的对象复制到另一块Survior2中.
  • 接下来就使用Survior2+Eden进行内存分配

通过这种方式,只需要浪费10%的内存空间即可实现带有压缩功能的垃圾收集方法,避免了内存碎片的问题.

一般情况下,经过15次分配后就进入了老年代区域

5.4 分代收集算法

根据对象存活周期的不同将Java堆划分为老年代和新生代,根据各个年代的特点使用最佳的收集算法.

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

推荐阅读更多精彩内容