GC和内存分配策略

程序计数器、虚拟机栈、本地方法栈的内存基本在编译器得到确定,但是堆和方法区中的内存的分配和回收是动态的,需要GC来管理

判断对象死活方法

引用计数算法(对象中增加引用计数算法,有一个地方引用该对象,计数器加1;引用失效,计数器减1,0的对象可以回收)缺点是相互循环引用的问题

根搜索算法 (从GC ROOTs往下搜索,若是一个对象到GC ROOTS不存在引用链,就可以回收了)

可以作为GC ROOTS的对象: 虚拟机栈和方法区中引用的对象

jdk1.2后,引用分为了强应用、软引用、弱引用和虚引用

强引用形如 Object obj=new Object(),只要强引用还存在,就绝对不会被回收

软引用。在内存溢出异常抛出之前,软引用会被列入回收范围进行回收,若是回收了以后,还是内存不足则抛出异常

弱引用。只要GC开始工作,就会被回收。

虚引用。该引用对对象生存时间完全没有影响。无法通过虚引用获得对象实例

根搜索不可达的对象,也不一定立刻回收。经历两次标记过程。步骤如下

  1. 经过根搜索不可达,就将该对象进行标记,并且筛选判断该对象有无必要执行finalize(),对象没有覆盖finalize或者finalize已经被执行过的话,就没有必要再执行了。
  2. 若是有必要执行finalize,将会被放入一个F队列中,然后挨个儿去触发finalize,再然后进行二次标记。注意是触发,jvm并不保证一定可以执行完毕,在执行这个方法的过程中,有对象重新进入引用链,那么二次标记会把它移出F队列,若是被二次标记,离死不远了。

垃圾回收算法

标记清除算法(首先标记需要回收的对象,标记完成后统一回收)。
缺点是(1) 效率低(2)会产生大量不连续的内存碎片(可能引起后边运行若需要分配较大内存对象而内存不够用导致提前GC)

标记整理算法。先完成标记,让所有存活对象向一端移动,清掉端边界之外内存

复制算法。8:1:1分为edge/survivor/survivor。每次使用edge和一个survivor,回收时将还存活的对象拷贝到另一个survivor。若是另一个survivor内存不够,老年代还可以做担保人(拷贝到老年代)。

分代收集算法。新生代:复制算法 老年代:标记算法

内存分配与回收

对象优先在新生代eden区分配

MinorGc是新生代的垃圾收集动作,非常频繁,速度较快。
Full/MajorGc 是老年代Gc。经常伴随至少一次minorGc

大对象直接进入老年代,避免在eden和survivor之间发生大量的内存拷贝。

长期存活的对象直接进入老年代。对象在eden出生并且经过一次minirGc还能存活的话,年龄+1,到15岁进入老年代。或者survivor中相同年龄对象大小总和超过survivor的一半,年龄大于等于该年龄的对象直接进入老年代

空间分配担保
发生MinorGc之前,老年代会判断当前老年代的可用内存大小是否大于每次晋升到老年代的平均内存大小,若是小于,直接进行FUllGc。如是大于,查看HandlePromotionFailure是否允许担保失败,允许的话就只进行minorGc即可,否则也要进行一次FullGc

JVM中的垃圾收集器

收集器没有最好的,还是要根据业务选择最适合的

Serial收集器

jdk1.3之前,这是EDEN垃圾收集的唯一选择。这是一个单线程收集器,更重要的是,当它工作时,JVM会停下别的工作,即一心一意收垃圾。实际上,因为这一特性,在单CPU环境下,它相比其他收集器的单线程最为简单高效。

ParNew收集器
它是Serial的多线程版本,即多条线程收集垃圾,但还是一心一意收垃圾,即别的工作线程没法正常工作

Pararrel Scavenge收集器
也是一个新生代收集器,也是使用复制算法,同时一心一意收垃圾。想比ParNew,它可以达到一个可控制的吞吐量。

吞吐量即 运行用户代码时间/(运行用户代码时间+垃圾收集时间)

同时Pararrel相比ParNew还具有自使用调节策略

CMS收集器
CMS收集器是一种获取最短回收停顿时间为目标的收集器,符合重视服务响应速度要求。基于标记清楚(COLLECT-MARK-SWEEP)
主要分为4部分:

  1. 初始标记
  2. 并发标记
  3. 重新标记
  4. 并发清除

初始标记和重新标记这两个阶段需要将工作线程停下来,初始标记只是标记一下Gc Roots能到达的地方,速度很快,并发标记就是在进行Gc Roots Tracing,重新标记是修正并发标记期间因为程序继续运行导致标记变动的那一部分对象的标记记录,这一部分比初始标记时间长,但是远比并发标记时间短。

整个过程中,并发标记和并发清除耗时最长,但是所幸这两个阶段收集线程可以和用户线程一起工作。注意,这个过程中用户线程还在产生垃圾,且这部分垃圾无法在本次收集中被CMS处理掉,被称为浮动垃圾,同时还要分一部分内存空间给工作线程,所以CMS不能像其他收集器一样等到填满老年代再收集,一般设为68%,当然,随具体情况而变,若是老年代增长不是很快,可以调大这一参数。若是CMS运行期间预留的内存无法满足程序正常运行,就会出现一次"Concurrent Mode Failure",虚拟机将采用Serial old收集器收集老年代,停顿时间加长,性能降低啦。

CMS基于标记清除,所以收集完毕后会有内存碎片问题,可以设置参数每隔收集几次就整理碎片下

G1 收集器

这个收集器基于标记整理,即不会存在内存碎片问题,同时可以非常准确的控制停顿时间。

G1的这一特性源于其能够避免全区域的垃圾回收,其将整个java堆分为若干个大小固定的区域,跟踪这些区域的垃圾堆积程度并维护一个优先列表,每次根据允许的收集停顿时间,优先回收垃圾最多的区域。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值