Java垃圾收集器及内存分配
来源:互联网 发布:js中对象的长度 编辑:程序博客网 时间:2024/04/27 22:15
Java垃圾收集器及内存分配
一、垃圾收集算法
1. 标记-清除算法
分为标记、清除两个阶段:首先标记出要回收的对象,在标记完成后统一回收掉被标记的对象,标记过程就是上文讲的二次标记。缺点:标记和清理的效率都不高;标记清理后会产生大量不连续的内存碎片,将导致程序运行过程中要分配大对象是没有足够的连续空间而不得不提前触发垃圾收集。
2. 复制算法
它将可用内存分为2块大小相等的区域,每次只使用其中一块,当这一块的内存用完时,将活着的对象全部复制到另外一块,然后将已使用过的那一块内存全部清理。实现简单,运行高效,但是内存需要缩小为原来的一般,代价太高。
在现在的商业虚拟机中用这种算法回收新生代,因为新生代的对象大都是朝生夕死的,并不需要按照1:1划分空间,而是将大小分为一块较大的Eden空间和两块叫小的Survivor空间,每次使用时只使用Eden和一块Survivor,回收时将它们中存活的对象都拷贝到另一块Survivor中,然后清理掉Eden和使用过的Survivor空间,不过在极端情况下,如果空白Survivor空间无法存放下仍然存活的对象时,使用内存分配担保机制,直接将新生代依然存活的对象复制到年老代内存中,同时对于创建大对象时,如果新生代中无足够的连续内存时,也直接在年老代中分配内存空间。
3. 标记-整理算法
而在老年代中复制算法显然不适用,于是有了标记-整理算法,标记过程用标记-清理,之后让所有的存活对象都向一端移动,然后清理掉端边界以外的内存。
4. 分代收集算法
一般将Java堆分为新生代和老年代,然后根据不同代的特点使用不同算法进行收集。
二、垃圾收集器
1. Serial收集器
单线程执行,使用复制算法。它在进行垃圾收集时,必须暂停其他所有的工作线程(用户线程)。是Jvm client模式下默认的新生代收集器。对于限定单个CPU的环境来说,Serial收集器由于没有线程交互的开销,专心做垃圾收集自然可以获得最高的单线程收集效率。
2. ParNow收集器
Serial收集器的多线程版本,除了使用多条线程进行垃圾收集之外,其余行为与Serial收集器一样。
3. Parallel Scavenge收集器
也是一个新生代收集器,也是使用复制算法,并且是并行的,parallel Scavenge收集器的特点是它的关注点与其他收集器不同,CMS等收集器的关注点是尽可能地缩短垃圾收集时用户线程的停顿时间,而parallel Scavenge收集器的目标则是达到一个可控制的吞吐量。吞吐量= 程序运行时间/(程序运行时间 + 垃圾收集时间),虚拟机总共运行了100分钟。其中垃圾收集花掉1分钟,那吞吐量就是99%。它提供两个参数用于控制吞吐量:-XX:MaxGCPauseMills设置最大垃圾收集停顿时间,-XX:GCTimeRatio设置吞吐量大小。
除此以外,还有一个-XX:UseAdaptiveSizePolicy开关参数。打开时,就不需要指定-Xmn(新生代大小);-XX:SurvivorRato(Eden与Survivor的比例)以及-XX:PretenureSizeshold(晋升老年代对象年龄)等细节参数,虚拟机将动态调节这一些。
4. Serial Old算法
Serial Old是Serial收集器的老年代版本,它同样使用一个单线程执行收集,使用“标记-整理”算法。主要使用在Client模式下的虚拟机。
5. Parallel Old算法
Parallel Old是Parallel Scavenge收集器的老年代版本,使用多线程和“标记-整理”算法。
6.CMS算法
CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。CMS收集器是基于“标记-清除”算法实现的,整个收集过程大致分为4个步骤:
* 初始标记
* 并发标记
* 重新标记
* 并发清除
其中初始标记、重新标记这两个步骤任然需要停顿其他用户线程。初始标记仅仅只是标记出GC ROOTS能直接关联到的对象,速度很快,并发标记阶段是进行GC ROOTS 根搜索算法阶段,会判定对象是否存活。而重新标记阶段则是为了修正并发标记期间,因用户程序继续运行而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间会被初始标记阶段稍长,但比并发标记阶段要短。
由于整个过程中耗时最长的并发标记和并发清除过程中,收集器线程都可以与用户线程一起工作,所以整体来说,CMS收集器的内存回收过程是与用户线程一起并发执行的。
优点:并发收集、低停顿
缺点:1、CMS收集器对CPU资源非常敏感。在并发阶段,虽然不会导致用户线程停顿,但是会占用CPU资源而导致引用程序变慢,总吞吐量下降。CMS默认启动的回收线程数是:(CPU数量+3) / 4。 2、无法处理浮动垃圾(在CMS并发清理阶段产生的新垃圾),也是由于在垃圾收集阶段用户线程还需要运行,即需要预留足够的内存空间给用户线程使用,因此CMS收集器不能像其他收集器那样等到老年代几乎完全被填满了再进行收集,需要预留一部分内存空间提供并发收集时的程序运作使用。在默认设置下,CMS收集器在老年代使用了68%的空间时就会被激活,也可以通过参数-XX:CMSInitiatingOccupancyFraction的值来提供触发百分比,以降低内存回收次数提高性能。要是CMS运行期间预留的内存无法满足程序其他线程需要,就会出现“Concurrent Mode Failure”失败,这时候虚拟机将启动后备预案:临时启用Serial Old收集器来重新进行老年代的垃圾收集,这样停顿时间就很长了。所以说参数-XX:CMSInitiatingOccupancyFraction设置的过高将会很容易导致“Concurrent Mode Failure”失败,性能反而降低。 3、,CMS是基于“标记-清除”算法实现的收集器,使用“标记-清除”算法收集后,会产生大量碎片。为了解决这个问题,CMS收集器提供了一个-XX:UseCMSCompactAtFullCollection开关参数,用于在Full GC之后增加一个碎片整理过程,还可通过-XX:CMSFullGCBeforeCompaction参数设置执行多少次不压缩的Full GC之后,跟着来一次碎片整理过程。
7、G1收集器
G1(Garbage First)收集器是JDK1.7提供的一个新收集器,G1收集器基于“标记-整理”算法实现,也就是说不会产生内存碎片。还有一个特点之前的收集器进行收集的范围都是整个新生代或老年代,而G1将整个Java堆(包括新生代,老年代)。
三、参数总结
-XX:+< option > 启用选项-XX:-< option > 不启用选项-XX:< option >=< number> -XX:< ption>=< string >
四、内存分配与回收
1、对象优先在Eden上分配
大多数情况下,对象在新生代Eden中分配,当Eden中没有足够的空间分配时会引起一次Minor GC。
注意:
新生代GC(Minor GC) 发生在新生代的垃圾收集动作,发生非常频繁,一般回收速度比较快。
老年代GC(Major GC/Full GC) 发生在老年代,出现major gc,经常会伴随着至少一次Minor GC(非绝对),速度一般比Minor GC慢10倍以上。
2、大对象直接进入老年代
大对象:需要大量连续内存空间的Java对象。虚拟机可通过-XX:PretenureSizeThreshold参数,令大于这个设置值的对象直接在老年代分配。
3、长期存活的对象将进入老年代
虚拟机会给每个对象定义一个对象年龄计数器。如果对象在Eden出生并经过第一次Minor GC后仍存活,并且能被Survivor接纳的话,将移到Survivor空间中,并将对象年龄设为1,对象在Survivor空间没熬过一次Minor GC,年龄就加一,当到一定数值(默认15)时,就会晋升到老年代中。可通过-XX:MacTenuringThreshold设置。
4、动态对象年龄判定
为了更好适应不同程度的内存状况,虚拟机并不总是要求对象的年龄到MaxTenurintThreshold才晋升老年代,如果Survivor空间中相同年龄的所有对象大小的总和大于Survivor空间的一半,年龄大于等于这个年龄的对象就会直接进入到老年代。
5、空间分配担保
在发生Minor GC时,虚拟机会检测之前每次晋升到老年代的平均大小是否大于老年代剩余大小,如果大于,则改为直接进行一次Full GC,如果小于,则查看HandlePromotionFailure设置是否允许担保失败,如果允许,那只会进行Minor GC,如果不允许,则改成一次Full GC。
- Java垃圾收集器及内存分配
- 【java基础 8】垃圾收集算法及内存分配策略
- JVM内存分配及垃圾收集器浅析
- Java垃圾收集器与内存分配策略
- Java虚拟机-垃圾收集器和内存分配机制
- JAVA 垃圾收集器与内存分配策略
- Java垃圾收集器与内存分配策略
- JAVA 垃圾收集器与内存分配策略
- java垃圾收集器与内存分配策略
- Java虚拟机垃圾收集器与内存分配策略
- Java 垃圾收集器与内存分配策略
- Java内存分配策略与垃圾收集器
- JAVA——垃圾收集器与内存分配策略
- Java垃圾收集器和内存分配策略
- JAVA垃圾收集器与内存分配策略
- java垃圾收集器与内存分配策略(1)
- java虚拟机之垃圾收集器与内存分配策略
- Java 垃圾收集与内存分配
- 1040. Longest Symmetric String (25)
- VC++多工程项目
- CodeForces 733E Sleep in Class
- 算法设计与分析实验四回溯法+子集树+最大团+0-1背包问题求解
- 2016 SWPU web7的复现与思考
- Java垃圾收集器及内存分配
- spring mvc的获取参数和传递参数
- 八小时学会html5视频笔记
- LeetCode 209. Minimum Size Subarray Sum
- ACM篇:POJ1001Exponentiation总结
- PAT(A) - 1015. Reversible Primes (20)
- UITableView reloadData结束之后
- 中断和异常管理
- Spring MVC 框架学习总结