垃圾收集器与内存分配策略

三个问题:1.哪些对象需要回收?2.什么时候回收?3.如何回收?

我们先来看第一个问题,哪些对象需要回收,这就需要判断哪些对象已经‘死亡’,哪些对象还在‘存活’着。通常的解决方法就是引用计数法:

给对象引用加一个计数器,当有一个地方引用它时,就加1,当一个引用失效就减1。最后计数器为0的时候就判定它是‘死亡’的。通常来说他的效率很高,但是在这里有一个无法解决的情况,那就是对象之间互相引用的问题,会导致计数器不会为0。


结果是

从程序中可以看出,即使a,b两个对象通过相互引用的方式来保持对象计数器的值不为零,但是任然会被垃圾回收器进行回收,jvm并不是用这个方法。

可达性分析算法:

基本思路就是通过分析名为GCRoot的起始点,开始向下搜索,搜索走过的路径称作引用链,当一个对象没有任何引用链到达Root的时候,就表明可以被回收了。


下面是什么时候回收呢?

引用分类:

强引用,只要引用还存在,那么就不会被垃圾收集器回收。

软引用,在发生内存溢出之前会对这些引用进行二次回收,如果还是没有足够的内存才会抛出异常。

弱引用,无论当前内存是否足够,收集器都会对这些引用进行回收操作。

虚引用,比弱引用还弱,只是在回收的时候,被关联虚引用的对象会收到一个系统通知。

finalize():

在可达性分析中的不可达对象,也是有机会翻盘的,并不是一定被kill。这些对象在宣布死亡的时候会进行两次标记操作,第一次标记操作是筛选出这些对象有没有必要执行finalize的方法,当对象没有覆盖finalize()或者执行过一次,那么就没有必要执行finalize方法了。为什么要执行finalize方法呢,首先,这些对象已经被宣告死亡,让他们执行finalize()是为了给他们一个辩解的机会,把自己(this)赋值给其他引用,那么在第二次标记的时候就会忽略掉。

当对象第二次被标记的时候,那就是死透了,没有机会了。

所以一个对象的finalize()方法在存活时候只能被执行一次。机会都是留给有准备的人的。


结果是

finalize method executed

yes, i'm alive

No, i'm dead

具体原因在代码中注释。


接下来看看如何回收呢。

垃圾收集算法:

标记清除:先标记要被回收的区域,然后清除掉,缺点是会存在内存碎片区域。

处理对象是要被回收的区域。

标记-清除法的缺点在于

1.标记阶段暂停的时间可能很长,而整个堆在交换阶段又是可访问的,可能会导致被换页换出内存。

2.另外一个问题在于,不管你这个对象是不是可达的,即是不是垃圾,都要在清楚阶段被检查一遍,非常耗时.

3,标记清楚这两个动作会产生大量的内存碎片,于是当有大对象进行分配时,不需要触发一次垃圾回收动作

复制清除

处理对象是存活的区域。适用于新生代。

将内存分为两个区域(from space和to space)。所有的对象分配内存都分配到from space。在清理非活动对象阶段,把所有标志为活动的对象,copy到to space,之后清楚from space空间。然后互换from sapce和to space的身份。既原先的from space变成to sapce,原先的to space变成from space。每次清理,重复上述过程。

优点:copy算法不理会非活动对象,copy数量仅仅取决为活动对象的数量。并且在copy的同时,整理了heap空间,即,to space的空间使用始终是连续的,内存使用效率得到提高。

缺点:默认情况下Eden:Survivor=8:1, 所以总会有100-(80+10)%的新生代内存会被浪费掉。


标记整理

类似清理,适用于存放生命周期较长对象的tenured generation:PSOldGen

1. 标记阶段, 这个阶段和标记-清除收集器的标记阶段相同

2. 整理阶段, 这个阶段将所有做了标记的活动对象整理到堆的底部。


安全点与安全区

程序在运行的过程中,收集器需要枚举GCRoot节点,但是需要暂停运行,当线程运行到safepoint的时候,会暂停,给收集器收集GCRoot节点的机会。同时当线程没有运行或无法到这个点的时候,为了解决这个问题,就将这个点扩大成一个区域,用来保证枚举GCRoot节点的成功。

垃圾收集器都是需要停顿来进行垃圾回收,影响运行效率,所以就出现了收集器的发展,各个收集器都有自己的优缺点,所以虚拟机会针对具体的应用场景进行组合使用。

内存分配与回收策略

新生对象优先在Eden区分配,当这个区域没有足够内存则会进行一次垃圾回收。

大对象直接进入老年区域,当过大的对象在Eden区及Survivor区都没有足够空间的情况下会进入老年区。

长期存活的对象进入老年代,在Eden区域中,进行一次垃圾回收后,仍然存活的对象会分配到Survivor区域(有足够的空间)。之后在每次GC后会将自己的一个年龄计数器加1,直到某个程度(默认15)后,会直接进入老年代。

动态对象年龄判定,虚拟机并非需要一个对象长期存活到某一年龄才会分配到老年代,如果Survivor对象中所有年龄相同的对象大小之和大于等于Survivor区域的一半,那么会直接进入老年代。

空间分配担保,新生代使用复制算法,当Minor GC时如果存活对象过多,无法完全放入Survivor区,就会向老年代借用内存存放对象,以完成Minor GC。在触发Minor GC时,虚拟机会先检测之前GC时租借的老年代内存的平均大小是否大于老年代的剩余内存,如果大于,则将Minor GC变为一次Full GC,如果小于,则查看虚拟机是否允许担保失败,如果允许担保失败,则只执行一次Minor GC,否则也要将Minor GC变为一次Full GC。说白了,新生代放不下就会借用老年代的空间来进行GC

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

推荐阅读更多精彩内容