内存分配与回收策略

本文大部分内容基本全部来源于《深入理解JAVA虚拟机》   周志明著。


  对象的内存分配,往大方向上讲,多数是在堆上分配,其中对象主要分配在Eden区,如果启动TLAB,将按照线程优先在TLAB上分配,但也有少数情况下会分配在老年区。

1.对象优先在Eden分配

首先介绍两种GC:①新生代GC,也叫Minor GC,指发生在新生代的垃圾回收动作,由于JAVA的大多数对象具有朝生夕灭的特性,因此这种GC发生的很频繁,回收速度也较快。

                            ②老年代GC,也叫Full GC或者Major GC,指发生在老年代的垃圾收集动作,经常伴随至少一次的Minor GC,但也不是绝对的,速度一般比Minor GC慢10倍以上。

  当Eden区没有足够的空间分配时,虚拟机会发起一次Minor GC,这里我们要知道的是新生区包括Eden区和一个Survivor区,但是是存在2个Survivor区的,2个Suivivor中必定有一个区是空的。因此新生代总的可用空间就是(Eden+1个Survivor)。如果分配时发现Eden区没有足够的内存,那么会发生一次Minor GC,这期间发生的动作会导致Eden区的对象进入一个Survivor区,如果虚拟机发现Eden区的对象太大以至于无法全部放入1个Survivor区,会通过分配担保机制提前将Eden区内的对象转移到老年代去。

2.大对象直接进入老年代

  因为新生代采用复制算法收集内存,因此大对象对于JVM是很苦恼的,尤其是当这些大对象很短命的时候,经常出现大对象容易导致内存还有不少空间时就提前出发垃圾收集以获取足够的连续空间来安置他们。

因此,当产生大对象时,会将其直接分配在老年代。

3.长期存活的对象将进入老年代

  虚拟机管理内存的思想是分代收集。每个对象定义了一个对象年龄计数器,当对象在Eden出生并经过第一次Minor GC后仍然存活,并且能被Survivor容纳的话,将被移动到Survivor中,并且其年龄被置为1,每度过一次GC(即每次从一个Survivor转移到另一个Survivor中),年龄增加1,当到达15岁时,晋升到老年代。15这个年龄值是可以人为改变的。但是并不是一定要到达年龄阀值时对象才会被转移到老年代,JVM中存在动态对象年龄判定来适应不同程序的内存状况。如果在Survivor空间中相同年龄的所有对象的大小总和大于Survivor空间的一半,这些对象可以提前直接进入老年代。

4.空间分配担保

  在发生Minor GC之前,JVM会先检查老年代最大可用的连续空间是否大于新生代所有对象的总空间(防止在经过这次Minor GC之后存活的新生代的所有对象年龄达到阀值或者满足动态对象年龄判定条件,导致进入老年代时,老年代空间不够----------这是个人理解),如果这个条件成立,那么Minor GC可以确保是安全的。如果不成立,会继续检查老年代最大可用连续空间是否大于历次晋升到老年代对象的平均大小,如果大于,尝试进行一次Minor GC,尽管这次Minor GC是有风险的;如果小于,那么不允许冒险,此时就需要进行一次Full GC来清理老年代。

    上文提到的冒险:新生代采用复制收集算法,但是为了内存利用率,只是用一个Survivor作为轮换备份,Minor GC后最极端的情况是新生代的所有对象都存活,这时Eden区的对象要进入Survivor区中,老年代要进行分配担保来把Survivor无法容纳的对象直接进入老年代。因为经过Minor GC后到底有多少对象存活在完成内存回收之前是未知的,因此取之前每次晋升到老年代对象的容量的平均大小作为经验值与老年代剩余空间进行比较来决定是否进行Full GC来让老年代腾出更多空间。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值