深入理解 Java 内存回收机制

JVM 通过 GC(Garbage Collection,垃圾回收器)来回收堆和方法区中的内存,这个过程是自动执行的。说到 Java GC 机制,其主要完成 3 件事:确定哪些内存需要回收;确定什么时候需要执行 GC;如何执行 GC。JVM 主要采用回收器的方式实现 GC,主要的回收器有引用计数回收器和跟踪回收器。

一、引用计数回收器

(1)引用计数器采用分散式管理方式,通过计数器记录对象是否被引用。当计数器为 0 时,说明此对象已经不再被使用,可进行回收。如图所示:

image

(2)引用计数器需要在每次对象赋值时进行引用计数器的增减,所以有一定消耗。另外,引用计数器对于循环引用的场景没有办法实现回收。例如在上面的例子中,如果 Object_2 和 Object_3 互相引用,那么即使 Object_1 释放了对 Object_2 和 Object_3 的引用,也无法回收 Object_2、Object_3,因此对于 java 这种会形成复杂引用关系的语言而言,引用计数器是非常不适合的。

二、跟踪回收器

跟踪收集器采用的是集中式的管理方式,会全局记录数据引用的状态。它基于特定的触发条件(例如定时、空间不足时),执行时需要从根集合来扫描对象的引用关系,这可能会造成应用程序暂停。主要有复制(Copying)、标记 - 清除(Mark-Sweep)和标记 - 压缩(Mark-Compact)三种实现算法。
1. 复制(Copying)
复制采用的方式为从根集合扫描出存活的对象,并将找到的存活对象复制到一块新的完全未被使用的空间中,如图所示:

image

复制收集器方式仅需要从根集合扫描所有存活对象,当要回收的空间中存活对象较少时,复制算法会比较高效(年轻代的 Eden 区就是采用这个算法),其带来的成本是增加一块空的内存空间以及需要进行对象的移动。

2. 标记 - 清除(marking-delete)
标记 - 清除采用的方式是从根集合开始扫描,对存活的对象进行标记,标记完毕后,再扫描整个空间中未标记的对象,并进行清除,标记和清除过程如下图所示:

image

上图中蓝色的部分是有被引用的存活的对象,褐色部分没被引用的可回收的对象。在标记阶段为了标记对象,所有的对象都会被扫描一遍,扫描的过程是比较耗时的。

image

清除阶段回收的是没有被引用的对象,存活的对象被保留。内存分配器会持有空闲空间的引用列表,当有分配请求时会查询空闲空间引用列表进行分配。标记 - 清除动作不需要进行对象移动,只需要对不存活的对象进行处理。在空间中存活对象较多的情况下较为高效,但由于标记 - 清除直接回收不存活对象占用的内存,因此会造成内存碎片。

3. 标记 - 压缩(Mark-Compact)
标记 - 压缩和标记 - 清除一样,是对活的对象进行标记,但是在清除后的处理不一样,标记 - 压缩在清除对象占用的内存后,会把所有活的对象向左端空闲空间移动,然后再更新引用其对象的指针,如下图所示:

image

很明显,标记 - 压缩在标记 - 清除的基础上对存活的对象进行了移动规整动作,解决了内存碎片问题,得到更多连续的内存空间以提高分配效率,但由于需要对对象进行移动,因此成本也比较高。

4. 分代式垃圾回收

分代收集算法是目前大部分 JVM 的垃圾收集器采用的算法。它的核心思想是是分而治之,根据对象存活的生命周期将内存划分为若干个不同的区域,再根据不同区域的特点来具体选择合适的垃圾回收方案。一般情况下,根据对象易产生垃圾的状态或者对象的大小,将堆区划分为老年代(Tenured Generation)和新生代(Young Generation)。堆内存分代策略如图所示。

image

(1)新生代也称 Young 区。新生代划分为一块较大的 Eden 空间(伊甸园)和 Survivor 空间(幸存者区)。eden 区也称伊甸园(《圣经》中亚当和夏娃出生的地方),很形象的比喻对象的出生地点,全部的新生对象都会出现在 eden 区。在 Survivor 幸存者空间中又分为 from 和 to 两块 (也称为 s0 和 s1),用于相互复制对象来进行垃圾清理。新生代的绝大部分对象有朝生熄灭的特点,存活率很低,每次垃圾回收时都有大量的对象需要被回收。目前大部分垃圾收集器对于新生代都采取复制回收算法,因为新生代中的对象创建时间不长,更新比较快。每次垃圾回收都要回收大部分对象,也就是说需要复制的操作次数较少。当进行回收时,将 Eden 和其中一块 Survivor 中还存活的对象复制到另一块 Survivor 空间中,然后清理掉 Eden 和刚才使用过的 Survivor 空间,如此循环下去。

(2)老年代也称 Old 区。老年代存放的是一些 “大对象” 以及新生代中经过多次垃圾回收仍然存活的对象。老年代中对象的生命周期较长,对象存活率较高。每次垃圾收集时只有少量对象需要被回收,产生垃圾少。针对这种情况,使用标记 - 压缩算法回收效率比较高。

(3)持久代也称 Permanent 区或方法区。存储类信息、常量、静态变量以及方法描述等信息。相对而言,垃圾回收行为在这个区域是比较少出现的,但并非数据进入了持久代就可以永久存在。对永久代的回收主要回收两部分内容:废弃常量和无用的类。

(4)分代垃圾回收过程如图所示

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