JVM调优系列:(四)GC垃圾回收
跟踪收集算法:
- 复制(copying):
将堆内分成两个同样空间,从根(ThreadLocal的对象。静态对象)開始訪问每个关联的活跃对象,将空间A的活跃对象所有拷贝到空间B,然后一次性回收整个空间A。由于仅仅訪问活跃对象,将所有活动对象复制走之后就清空整个空间,不用去訪问死对象,不须要标记骤,所以遍历空间的成本较小,但须要巨大的复制成本和较多的内存。
- 标记清除(mark-sweep):
收集器先从根開始訪问全部对象,标记活跃对象。然后再遍历一次整个内存区域。把全部没有标记活跃的对象进行回收处理。该算法遍历整个空间的成本较大暂停时间随空间大小线性增大。并且标记结束后,相邻的不可触及对象所占空间会合并在一起,但不会进行整理,将产生越来越多的碎片。
- 标记整理(mark-sweep-compact):
收集器先从根開始訪问全部对象,先标记活跃对象,然后清除未标记的对象,再将堆中活跃对象拷贝到堆的底部,使活跃对象紧凑的排列在一起,避免碎片产生。
经常使用GC收集器类型:
- 1.单CPU串行收集器(Serial Collector)
使用 -XX:+UseSerialGC,策略为:
年轻代串行复制,-XX:MaxTenuringThreshold来设置对象复制的次数。
年老代串行标记整理。
- 2.吞吐量优先的并行收集器(Throughput Collector)
使用 -XX:+UseParallelGC 。也是JDK -server的默认值, 它不能和CMS配合使用。策略为:
1.年轻代暂停应用程序,多个垃圾收集线程并行的复制收集,线程数默觉得CPU个数,CPU非常多时,可用–XX:ParallelGCThreads=线程数。
2.年老代暂停应用程序。与串行收集器一样,单垃圾收集线程标记整理。
使用-XX:+UseParallelOldGC打开年老代并行垃圾回收的线程数.
能够使用-XX:MaxGCPauseMillis 和 -XX:GCTimeRatio 来调整GC的时间。
-XX:MaxGCPauseMillis=毫秒:指定垃圾回收时的最长暂停时间,假设指定了此值的话。堆大小和垃圾回收相关參数会进行调整以达到指定值。
-XX:GCTimeRatio : 吞吐量为垃圾回收时间与非垃圾回收时间的比值。公式为1/(1+N)。比如,-XX:GCTimeRatio=19时,表示5%的时间用于垃圾回收。默认情况为99,即1%的时间用于垃圾回收。
Parallel Copying Collector用-XX:UseParNewGC參数配置,它主要用于新生代的收集,此GC能够配合CMS一起使用。
Parallel Mark-Compact Collector用-XX:UseParallelOldGC參数配置,此GC主要用于老生代对象的收集(jdk1.6)。
- 3.暂停时间优先的并发收集器(Concurrent Low Pause Collector-CMS)
使用-XX:+UseConcMarkSweepGC, 主要用于老生代,策略为:
1.年轻代相同是暂停应用程序。多个垃圾收集线程并行的复制收集。
2.年老代则仅仅有两次短暂停,其它时间应用程序与收集线程并发的清除。
採用两次短暂停来替代标记整理算法的长暂停,它的收集周期: 初始标记(CMS-initial-mark) -> 并发标记(CMS-concurrent-mark) -> 又一次标记(CMS-remark)-> 并发清除(CMS-concurrent-sweep) ->并发重设状态等待下次CMS的触发(CMS-concurrent-reset)。
它的主要适合场景是对响应时间的重要性需求大于对吞吐量的要求,可以承受垃圾回收线程和应用线程共享处理器资源,而且应用中存在比較多的长生命周期的对象的应用。但CMS收集算法在最为耗时的内存区域遍历时採用多线程并发操作,但对于serverCPU资源不够的情况下。事实上对性能是没有提升的,反而会导致系统吞吐量的下降;
CMS默认启动的回收线程数目是 (ParallelGCThreads+ 3)/4) 。能够通过来设定
-XX:ParallelGCThreads=N 来调整年轻代的并行收集线程数, 年轻代的并行收集线程数默认是(cpu <= 8) ? cpu : 3 +((cpu * 5) / 8).
-XX:ParallelCMSThreads=N调整CMS收集线程数,CMS默认启动的回收线程数目 (ParallelGCThreads+ 3)/4)
-XX:+UseCMSCompactAtFullCollectionCMS是不会整理堆碎片的。因此为了防止堆碎片引起full gc,通过会开启CMS阶段进行合并碎片选项. 为了降低第二次暂停的时间,开启并行remark:-XX:+CMSParallelRemarkEnabled。
假设remark还是过长的话,能够开启-XX:+CMSScavengeBeforeRemark选项。强制remark之前開始一次minor
gc,降低remark的暂停时间,可是在remark之后也将马上開始重新minor gc.
-XX:+CMSClassUnloadingEnabled-XX:+CMSPermGenSweepingEnabled普通情况下。持久代是不会进行GC的,通过以上參数进行强制设置。
-XX+UseCMSCompactAtFullCollection 在FULL GC的时候, 对年老代的压缩
-XX:CMSFullGCsBeforeCompaction对年老代的压缩开启的情况下,多少次FULL GC后进行内存压缩,整理
-XX:+UseCMSInitiatingOccupancyOnly 指示仅仅有在old generation在使用了初始化的比例后concurrentcollector启动收集
-XX:CMSInitiatingOccupancyFraction=80默认CMS是在tenured generation沾满68%的时候開始进行CMS收集, 假设你的年老代增长不是那么快。而且希望减少CMS次数的话,能够适当调高此值
-XX:+AggressiveHeap 试图是使用大量的物理内存,长时间大内存使用的优化,CMS收集生效
-XX:+CMSIncrementalMode设置为增量模式, 单CPU情况使用
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvb3BlbnN1cmU=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" width="600" height="230" alt="">
-XX:+UseAdaptiveSizePolicy 设置此选项后。并行收集器会自己主动选择年轻代区大小和对应的Survivor区比例,以达到目标系统规定的最低对应时间或者收集频率等,此值建议使用并行收集器时。一直打开。
-XX:MaxGCPauseMillis=100 设置每次年轻代垃圾回收的最长时间。假设无法满足此时间,JVM会自己主动调整年轻代大小。以满足此值
-XX:GCTimeRatio=19 设置垃圾回收时间占程序执行时间的百分比,公式为1/(1+N),默认情况为99。即1%的时间用于垃圾回收。
JVM GC机制:
在Java语言里面,可作为GC Roots的节点主要在全局性的引用(比如常量或类静态属性)与运行上下文(比如栈帧中的本地变量表)中。假设要使用可达性分析来推断内存是否可回收的,那分析工作必须在一个能保障一致性的快照中进行——这里“一致性”的意思是整个分析期间整个运行系统看起来就像被冻结在某个时间点上,不能够出现分析过程中,对象引用关系还在不断变化的情况,这点不满足的话分析结果准确性就无法保证。这点也是导致GC进行时必须暂停的当中一个重要原因.
HOTSPOT使用准确式GC, 从外部记录下类型信息,存成映射表。HotSpot把这种数据结构叫做OopMap,须要虚拟机里的解释器和JIT编译器都有相应的支持,在类载入完毕的时候,HotSpot就把对象内什么偏移量上是什么类型的数据计算出来,在JIT编译过程中。也会在特定的位置记录下栈里和寄存器里哪些位置是引用, 这样GC在扫描时就就能够直接得知这些信息了。HotSpot是用“解释式”的方式来使用OopMap的,每次都循环变量里面的项来扫描相应的偏移量。
解释式: 每次都遍历原始的映射表,循环的一个个偏移量扫描过去,HOTSPOT採用
编译式: 为每一个映射表生成一块定制的扫描代码(想像扫描映射表的循环被展开的样子)。以后每次要用映射表就直接运行生成的扫描代码。
在OopMap的协助下,HotSpot能够高速准确地地完毕GC Roots枚举。但一个非常现实的问题随之而来,可能导致引用关系变化。或者说OopMap内容变化的指令非常多,假设为每一条指令都生成相应的OopMap,那将会须要大量的额外空间,这样GC的空间成本将会变得非常高。
所以HotSpot也的确没有为每条指令都生成OopMap,前面已经提到,仅仅是在“特定的位置”记录了这些信息,这些位置被称为安全点(Safepoint),即程序运行时并不是在全部的地方都能停顿下来開始GC,仅仅有在到达安全点时才干暂停。
每一个被JIT编译过后的方法也会在安全点记录下OopMap,记录了运行到该方法的某条指令的时候,栈上和寄存器里哪些位置是引用。
这样GC在扫描栈的时候就会查询这些OopMap就知道哪里是引用了。
Safepoint的选定既不能太少以至于让GC等待时间太长。也不能过于频繁以至于过分增大运行时的负荷。所以安全点的选定基本上是以程序“是否具有让程序长时间运行的特征”为标准进行选定:
1、循环的末尾
2、方法临返回前 / 调用方法的call指令后
3、可能抛异常的位置
怎样让GC发生时,让全部线程(这里不包含运行JNI调用的线程)都跑到近期的安全点上再停顿下来。HotSpot採用主动式中断,主动式中断的是当GC须要中断线程的时候,不直接对线程操作。只简单地设置一个标志,各个线程运行时主动去轮询这个标志,发现中断标志为真时就自己中断挂起。
对Java线程中的JNI方法,它们既不是由JVM里的解释器运行的,也不是由JVM的JIT编译器生成的,所以会缺少OopMap信息,HotSpot的解决方法是:全部经过JNI调用边界(调用JNI方法传入的參数、从JNI方法传回的返回值)的引用都必须用“句柄”(handle)包装起来。JNI须要调用Java API的时候也必须自己用句柄包装指针。在这样的实现中,JNI方法里写的“jobject”实际上不是直接指向对象的指针,而是先指向一个句柄,通过句柄才干间接訪问到对象。
这样在扫描到JNI方法的时候就不须要扫描它的栈帧了,仅仅要扫描句柄表就能够得到全部从JNI方法能訪问到的GC堆里的对象。
内存回收怎样进行是由虚拟机所採用的GC收集器所决定的。而通常虚拟机中往往不止有一种GC收集器,眼下HotSpot里面就包括有经常使用的garbage collectors:
· serial collector :针对younggeneration的串行垃圾收集器,使用stop-the-world(就是暂停整个应用程序的运行)的形式。利用单线程通过复制live objects到survivor space或tenured generation的方法来进行垃圾收集。
· parallel scavenge collector :针对younggeneration的并行垃圾收集器,利用多个GC线程来进行垃圾收集,每一个线程的GC方法和serial collector一样。
· parallel new collector :针对younggeneration的增强的并行垃圾收集器,以便能够和CMS一起使用。
· serial old collector :针对tenuredgeneration的串行垃圾收集器,使用stop-the-world形式,利用单线程通过mark-sweep-compact的方法进行垃圾收集。
· parallel old collector :针对tenuredgeneration的并行垃圾收集器,利用多线程进行垃圾收集,方法和serial old collector一样。
· parallel compacting collector :对于younggeneration使用和parallel new collector一样的算法。对于tenured generation使用了新的算法(mark-summary-compact),该收集器用来替代parallel new collector和parallel oldcollector。
· concurrent mark-sweep collector :对于younggeneration使用和parallel new collector一样的算法,对于tenured generation使用跟应用程序并发的方式,收集期间也有引起stop-the-world的暂停Mark阶段,也有伴随着应用程序执行的并发 Mark和并发Sweep阶段。减少了应用程序暂停的时间。
能够看出这些垃圾收集器分为3种类型:串行。并行,并发。
JVM调优系列:(四)GC垃圾回收的更多相关文章
- JVM 调优系列之图解垃圾回收
摘要: jvm必知系列,总结一些常见jvm回收机制,方便查阅 对于调优之前,我们必须要了解其运行原理,java 的垃圾收集Garbage Collection 通常被称为"GC", ...
- java虚拟机学习-JVM调优总结-分代垃圾回收详述(9)
为什么要分代 分代的垃圾回收策略,是基于这样一个事实:不同的对象的生命周期是不一样的.因此,不同生命周期的对象可以采取不同的收集方式,以便提高回收效率. 在Java程序运行的过程中,会产生大量的对象, ...
- jvm 调优(2)垃圾回收算法
可以从不同的的角度去划分垃圾回收算法: 按照基本回收策略分 引用计数(Reference Counting): 比较古老的回收算法.原理是此对象有一个引用,即增加一个计数,删除一个引用则减少一个计数. ...
- java虚拟机学习-JVM调优总结-新一代的垃圾回收算法(11)
垃圾回收的瓶颈 传统分代垃圾回收方式,已经在一定程度上把垃圾回收给应用带来的负担降到了最小,把应用的吞吐量推到了一个极限.但是他无法解决的一个问题,就是Full GC所带来的应用暂停.在一些对实时性要 ...
- JVM调优-Jva中基本垃圾回收算法
从不同的的角度去划分垃圾回收算法. 按照基本回收策略分 引用计数(Reference Counting) 比较古老的回收算法.原理是此对象有一个引用,即增加一个计数,删除一个引用则减少一个计数.垃圾回 ...
- JVM调优(四)——tomcat远程debug
JVM调优(四)--tomcat远程debug tomcat远程debug jdwp协议 使用步骤 登录远程服务器,进入tomcat目录,并打开文件: //tomcat/bin/startup.sh ...
- [转] JVM 调优系列 & 高并发Java系列
1.JVM调优总结(1):一些概念:http://www.importnew.com/18694.html 2.JVM调优总结(2):基本垃圾回收算法:http://www.importnew.com ...
- JVM调优——之CMS GC日志分析
最近在学习JVM和GC调优,今天总结下CMS的一些特点和要点,让我们先简单的看下整个堆年轻代和年老代的垃圾收集器组合(以下配合java8完美支持,其他版本可能稍有不同),其中标红线的则是我们今天要着重 ...
- Android性能调优篇之探索垃圾回收机制
开篇废话 如果我们想要进行内存优化的工作,还是需要了解一下,但这一块的知识属于纯理论的,有可能看起来会有点枯燥,我尽量把这一篇的内容按照一定的逻辑来走一遍.首先,我们为什么要学习垃圾回收的机制,我大概 ...
随机推荐
- pagination使用说明
参考自张鑫旭 准备工作 下载jquery.min.js 下载jquery.pagination.js 下载pagination.css 开始敲代码 第一步,引入刚刚下载的三个文件 <link r ...
- HYSBZ-1040 骑士 基环树上的树状dp
题目链接:https://cn.vjudge.net/problem/HYSBZ-1040 题意 Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英. 他们劫富济贫,惩恶扬善,受到社会各界的 ...
- ip iproute2的典型应用
net-tools和iproute2的命令做对比,做到简单明了,分别演示如何去获取.配置和操作系统网络信息. 以下是net-tools和iproute2的大致对比: 4.1 ip link set-- ...
- Mysql学习总结(23)——MySQL统计函数和分组查询
1.使用count统计条数:select count(字段名...) from tablename; 2.使用avg计算字段的平均值:select avg(字段名) from tablename: 这 ...
- jquery.validate动态更改校验规则 【转】
有时候表单中有多个字段是相互关联的,以下遇到的就是证件类型和证件号码的关联,在下拉框中选择不同的证件类型,证件号码的值的格式都是不同的,这就需要动态的改变校验规则. <!DOCTYPE html ...
- 009实现一个算法来删除单链表中的一个结点,仅仅给出指向那个结点的指针(keep it up)
呵呵,这个题不能直接删除已知的结点.由于是单链表,不知道前驱,仅仅知道 后继结点,直接删除会使链表断开.只是我们能够删除已知结点的后继结点, 把后继结点的值赋值给已知结点. #include < ...
- 可替代google的各种搜索引擎
http://www.aol.com http://www.duckduckgo.com http://www.gfsoso.com http://www.googlestable.com http ...
- POJ 2442 Sequence(堆的使用练习)
题目地址:id=2442">POJ 2442 真心没想到这题的思路. .原来是从第一行逐步向下加,每次都仅仅保存前n小的数.顺便练习了下堆.. 只是感觉堆的这样的使用方法用的不太多啊. ...
- 51nod-1296: 有限制的排列
[传送门:51nod-1296] 简要题意: 有一个集合,集合中的数为1到n 给出a限制条件,a[i]表示第a[i]位置的数要比相邻位置的数要小 给出b限制条件,b[i]表示第b[i]位置的数要比相邻 ...
- 熟悉了下HTTP协议
HTML是一种用来定义网页的文本,会HTML,就可以编写网页: HTTP是在网络上传输HTML的协议,用于浏览器和服务器的通信.200表示一个成功的响应,后面的OK是说明.失败的响应有404 Not ...