Java 垃圾回收机制

垃圾回收机制让开发者不需要考虑内存管理,这样不仅提高了开发效率,还改善了内存的使用状况。

Java堆内存

堆在JVM启动时被创建,用来维护运行时数据, 运行时创建的对象都是基于这块内存空间,如果动态创建的对象没有得到及时回收,则会持续堆积造成堆空间被占满,最终内存溢出。

因此Java提供了一种垃圾回收机制,在后台创建一个守护进程。会自动把堆空间的垃圾全部进行回收,从而保证程序的正常运行。

垃圾收集算法

Java语言规范没有明确的说明JVM使用哪种垃圾回收算法,但是垃圾收集算法一般都要做以下两件事:

  1. 发现垃圾(无用、不再存活的对象);
  2. 回收被垃圾占用的内存空间。

大多数的垃圾回收算法使用了根集(root set)这个概念;垃圾回收首先会确定从根开始哪些是可达的,哪些是不可达的,从根集可达的对象是活动的对象,它们不能作为垃圾被回收。从根集通过任意路径不可达的对象被认为是应该被回收的垃圾。

根集:正在运行的Java程序可以访问的引用变量的集合(包括局部变量、参数、类变量)。程序可以使用引用变量访问对象的属性和调用对象的方法。

常见的垃圾回收算法有以下几种:

引用计数法

引用计数法没有使用根集概念。该算法使用引用计数器来区分存活对象和不再使用的对象。每一个创建的对象会对应一个引用计数器,存储该对象被引用的次数。当每一次创建一个对象并赋值给任意变量时,引用计数器的值置为1。当对象被赋给任意变量时,引用计数器值会每次加1。当对象出了作用域后(变量取消引用该对象),引用计数器值会减1,当引用计数器值为零时,意味着没有任何变量再使用这个对象(认为这个对象不再存活)。

基于引用计数器的垃圾收集器运行较快,不会长时间中断程序执行,但引用计数器增加了程序执行开销,且这种方案存在严重的问题,它无法检测“循环引用”:当两个对象互相引用,即使它俩都不被外界任何东西引用,它俩的计数都不为零,永远不会被垃圾回收器回收。

可达性分析

可达性分析算法是为了解决引用计数法的问题而提出的,它使用了根集的概念,把所有对象想象成一棵树,从根节点出发,将可达的对象标记为“存活”。其余的对象则被视为“死亡”(不可达的)。

基于可达性分析算法的垃圾收集也被称为标记和清除垃圾收集算法。

根集本身一定是可达的,这样从它们触发遍历到的对象才能保证一定可达。

Java中一定可达的对象主要有以下四种:

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

回收垃圾机制

参考下图,黑色的表示垃圾,灰色表示存活对象,绿色表示空白空间。

堆空间内存使用情况

要如何回收这些垃圾呢?

标记 - 清理
  1. 标记垃圾对象:所谓“标记”就是利用可达性遍历堆内存,把“存活”对象和“垃圾”对象进行标记,得到的结果如上图;
  2. 清理垃圾对象:把所有“垃圾”对象所占的空间清理回收。

结果如下:

标记 - 清理

这便是标记 - 清理方案,方便简单但是容易产生内存碎片。

标记 - 整理

为了解决内存碎片问题,在清理的时候,把所有存活的对象重新扎堆到同一片内存区域,这样就解决了内存碎片的问题。

标记 - 整理

以上两种方案适合存活对象多,垃圾少的情况。只需要清理掉少量的垃圾。然后挪动存活对象就可以。

复制

复制方法直接把堆内存分成两部分,一段时间内只允许在其中一块内存上进行分配,当这块内存被分配完后,则执行垃圾回收,把所有存活的对象复制到另一块内存上,然后清空当前内存。

扫描内存块
复制并清空当前内存

最初只使用上部分的内存,直到内存使用完毕,进行垃圾回收,把所有存活对象复制到下部分,然后清空上部分内存。

这种做法不容易产生碎片,也简单粗暴;但是这意味着在一段时间只能使用一部分的内存,如果内存容量较小,意味着堆内存会频繁的复制清空。

复制方案适合存活对象少,垃圾多的情况,这样在复制时就不需要复制多少对象到另一块内存,多数垃圾直接被清空。

Java堆结构

一块Java堆空间一般分成三个部分,这三部分用来存储三类数据:

  • 刚刚创建的对象。在程序运行时会持续不断地创造新的对象,这些对象会被统一放在一起。因为有很多局部变量等在新创建后很快就会变成不可达的对象,快速死去,因此这块区域的特点是存活对象少,垃圾多。可以形象的描述这块区域为:新生代;
  • 存活了一段时间的对象。这些对象被创建了很久,并且一直活了下来。这些存活时间较长的对象会被放在一起,他们的特点是存活对象多,垃圾少。可以形象的描述这块区域为:老年代;
  • 永久存在的对象。比如一些静态文件,这些对象的特点是不需要垃圾回收,永远存活。可以形象的描述这块区域为: 永生代(Java 8中已经把永久代删除,把这块内存空间给了元空间)

结合新生代和老年代的对象特点,对应的回收机制也不同,

新生代 - 复制 回收机制

由于新生代内存区域,会有大量新对象死去,只有少量存活。因此适合采用复制 回收算法,GC时把少量的存活对象复制到另一片内存。

针对复制算法,有以下几种思路:

  1. 把内存平均分成两等分:这样做的问题是内存空间的利用率很低只有一半的空间可以使用,对于新生代而言垃圾回收事件会发生的很频繁,影响正常程序运行。
  2. 把内存分成大小不等的两部分:如果划分的两部分的内存大小差异很小,则算法退化成了平分复制算法;如果大小差异很大,会存在一个很严重的问题,假设两个内存块的内存比例为1:9,由于内存空间比例相差很大,这就意味着,当从内存比例为9的内存区复制到内存比例为1的内存区时,由于内存区装不下那么多对象,而使得那些并不老的对象被放到了老年区,这就破坏了规则,且影响了老年区的垃圾回收的效率。
  3. 将内存分成一大两小三份(例如8:1:1),为了方便解释,将三个分区按序编号为1、2、3。首先1对外提供内存,快满时进行垃圾回收,将存活对象放入2;1清空后对外继续提供堆内存;当1再次被填满,此时对1和2同时进行垃圾回收,将存活对象存入3,同时清空1和2的内存;1继续对外提供内存,填满时进行垃圾回收把存活对象存入2,清空1和3的内存;重复上述操作...(这样便能确保进入老年代内存区的是真正的老对象)

显而易见最优的思路是3,因为觉得没必要展开来讲,偷个懒用文字表述了=V=。

老年代 - 标记整理 回收机制

由于老年代一般存放的是存活时间较久的对象,所以每次GC时,只有少部分对象被回收。因此选择使用标记整理垃圾回收机制,仅仅通过少量地移动对象就能清理垃圾,而且不存在内存碎片问题。

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

推荐阅读更多精彩内容