java虚拟机之GC(转)
垃圾回收主要内容:
1. 那些内存需要回收?
2. 什么时候回收?
3. 如何回收?
垃圾回收主要针对运行时数据区那些区域?
运行时数据区的线程私有区域有:虚拟机栈,本地方法栈,程序计数器等;
栈中的栈帧随着方法的进入和退出执行入栈和出栈,每个栈帧的内存分配在编译期就已经确定;
随着线程或方法的结束,内存也随着回收;
运行时数据区的线程共享区域有:方法区,堆;
方法区和堆只有程序处于运行期才能确定创建那些对象,因此这部分内存分配和回收都是动态的;
垃圾回收的重点区域;
一,对象存活判断
1,引用计数算法
给对象添加一个引用计数器,被引用时计数器值+1,引用失效计数器值-1,当计数器值为0时对象不可能再被使用;
主流Java虚拟机未选用该算法管理内存(未解决对象之间相互循环引用的问题)
实现简单,判断效率高(应用:FlashPlayer,Python等)
2,可达性分析算法
将"GC Roots"对象作为起始节点,向下搜索,搜索走过的路径为引用链;当一个对象到GC Roots没有引用链时,则该对象是不可用的;
可作为"GC Roots"的对象:
【1】,方法区中静态属性引用的对象
【2】,方法区中常量引用的对象
【3】,虚拟机栈引用的对象 (栈帧中本地变量表)
【4】,本地方法栈中JNI引用的对象 (Native方法)
二,垃圾回收算法
1,标记-清除算法
定义:先标记要回收的对象,然后统一回收;
适用:存活对象较多的垃圾回收
缺点:
【1】,效率低; 标记和清除的过程效率不高;
【2】,空间问题; 标记清除后产生大量不连续的内存碎片,给大对象分配内存时没有足够连续的内存空间,导致提前出发垃圾回收动作。
2,复制算法
定义:将可用内存划分成相等大小两块,每次只使用其中一块,当这一块用完后将还存活的对象复制到另一块,
然后将已使用过的内存一次清理。
适用:存活对象较少的垃圾回收
优点:每次对整个半区进行内存回收,不用考虑内存碎片问题,只要移动堆顶指针,按顺序分配内存即可;
实现简单,运行高效
缺点:将内存缩小了一半
其他:
将新生代内存按照8:1:1分为Eden,From Survivor,To Survivor三个空间,每次使用Eden和From Survivor两个空间给对象分配内存,
当内存不足垃圾回收时,将存活对象复制到To Survivor空间,然后清理Eden和From Survivor空间;这样相当于内存指浪费了10%;
如果10%的To Survivor空间不够存放存活对象时需要老年代进行分配担保(将存活对象通过分配担保机制直接进入老年代)
3,标记-整理算法
定义:先标记要回收的对象,将存活对象移至一端,最后清理端边界以外的内存
4,分代收集算法
定义:根据对象存活周期将内存划分为新生代和老年代,然后根据每个年代的特点使用合适的回收算法;
如:新生代存活对象少可以采用复制算法; 老年代存活对象多并且没有分配担保必须使用标记清理或标记整理回收算法
三,垃圾回收器
1,Serial收集器
定义:单线程收集器,收集时必须暂停其他所有用户线程,直到收集结束。
适用:新生代
配置:
-XX:PretenureSizeThreshold
-XX:HandlePromotionFailure
其他:
【1】,单CPU环境Serial收集器没有现成交互开销,因此单线程的收集效率最高
【2】,对于Client模式下的桌面应用,分配给虚拟机的内存不会很大,对于一两百兆的新生代内存回收停顿时间完全控制在一百多毫秒以内,
停顿不频繁发生,Serial收集器是最好的选择;
【3】,收集过程会暂停服务(Stop the world)
2,ParNew收集器
定义:是Serial收集器的多线程版本
适用:新生代
配置:
-XX:PretenureSizeThreshold
-XX:HandlePromotionFailure
-XX:+UseConcMarkSweepGC (设置默认新生代收集器)
-XX:+UserParNewGC (指定ParNew作为新生代收集器)
-XX:ParallelGCThreads(限制垃圾收集的线程数)
其他:
【1】,与Serial收集器的控制参数,收集算法,Stop the world,对象分配规则,回收策略完全一样
【2】,是运行Server模式下虚拟机首选新生代收集器(唯一能和CMS收集器配合工作)
CMS是并发收集器,第一次实现让收集线程和用户线程同时工作;
CMS属老年代收集器,无法与Parallel Scavenge配合工作;
CMS关注回收的停顿时间(暂停用户线程时间),停顿时间越短越适合于用户交互的程序,因为有较高的响应速度
【3】,单CPU环境没有Serial收集器效率高
【4】,并行的多线程收集器
3,Parallel Scavenge收集器
定义:和ParNew收集器一样的收集器,区别于主要关注吞吐量的控制和GC自适应调节策略;
注: 吞吐量 = 运行用户代码时间 / (运行用户代码时间 + 垃圾收集时间) ; 如果虚拟机总共运行100分钟,收集花费1分钟,则吞吐量为99%
适用:新生代; 较高的吞吐量,导致高效率的CPU利用率,主要适合后台运算
配置:
-XX:MaxGCPauseMillis (控制回收停顿的最大时间 ; 注:时间越小会牺牲吞吐量和新生代空间)
-XX:GCTimeRatio (设置吞吐量 0< X < 100 ; 垃圾回收时间占总时间的比例, 吞吐量的倒数)
如果将GCTimeRatio设置为19,最大GC时间占总时间的5%(即1/(1+19))
该值默认为99,则最大GC时间为1%
-XX:+UseAdaptiveSizePolicy (打开GC自适应调节策略)
GC自适应调节策略:虚拟机根据当前系统性能,自动调节参数已提供最合适的时间和最大吞吐量;
调节的参数包括:①,新生代大小(-Xmn),Eden和Survivor空间比例(-XX:SurvivorRatio)
②,晋升老年代对象的年龄(-XX:PretenureSizeThreshold)
... ...
GC自适应调节策略将内存管理交给虚拟机完成,只需要设置基本内存(-Xmx),停顿时间(MaxGCPauseMillis),吞吐量 (GCTimeRatio)等参数给虚拟机设立优化目标;
其他:
【1】并行:多条垃圾回收线程并行工作,单用户线程处于等待状态
并发:用户线程和回收线程同时进行
【2】,并行的多线程收集器
4,Serial Old收集器
定义:是Serial收集器的老年代版本的单线程收集器
适用:老年代(标记-整理算法); 主要给Client模式下的虚拟机使用;
其他:
如果在Server模式下主要有两大用途:①,在JDK1.5及之前的版本中与Parallel Scavenge收集器搭配使用
②,作为CMS收集器的后备预案(并发收集发生Concurrent Mode Failure时使用)
5,Parallel Old收集器
定义:是Parallel Scavenge收集器的老年代版本的多线程收集器
使用:老年代(标记-整理算法)
其他:
【1】,JDK1.6开始提供该收集器
6,CMS收集器(Concurrent Mark Sweep)
定义:CMS是一款并发收集,低停顿的收集器
关注目标:最短回收停顿时间
适用:互联网站,B/S系统服务端(较快的响应速度,最短的系统停顿时间)较好的用户体验
算法:标记-清除
回收步骤:
【1】初始标记(标记GC Roots能直接关联到的对象)(stop the world)
【2】并发标记(进行GC Roots Tracing的过程)
【3】重新标记(修正并发标记期间因用户程序继续运行而导致标记产生变动的对象的标记记录)(stop the world)
【4】并发清除
执行时间:
T(并发标记,并发清除) > T(重新标记) > T(初始标记)
由于耗时最长的并发标记和并发清除和用户线程一起工作,因此总体上CMS回收过程和用户线程一起并发执行的。
配置:
-XX:+UseConcMarkSweepGC 使用CMS收集器
-XX:ParallelCMSThreads 设定CMS的线程数量(一般情况约等于可用CPU数量)
缺点:
【1】对CPU资源非常敏感
并发阶段会占用部分线程(CPU资源)导致应用程序变慢,总吞吐量降低。
CMS默认回收线程数 = (CPU数量 + 3)/4; CPU数量↑回收线程↓; CPU数量=4时回收线程占用25%CPU资源;
CPU数量 < 4时,如CPU数量=2,则回收线程会占用一半CPU资源,导致用户程序执行速度直接降低50%,i-CMS收集器可以解决此问题;
增量式并发收集器(i-CMS): 并发标记和并发清理时让GC线程和用户线程交替运行,尽量减少GC线程独占资源的时间
【2】无法处理浮动垃圾,可能出现Concurrent Mode Failure失败而产生Full GC
并发清理时用户线程还在运行而不断产生的垃圾,由于在标记之后,CMS无法当次收集清理,只能等下次GC时清理,这部分垃圾称为“浮动垃圾”;
由于当次无法处理浮动垃圾,这些浮动垃圾又占有一定内存,又考虑要预留给用户线程足够的内存,因此让老年代提供预留空间;
因此CMS默认老年代使用68%时触发一次回收,百分比配置(-XX:CMSInitiatingOccupancyFraction)
如果CMSInitiatingOccupancyFraction参数设置过高,预留空间不足就会出现Concurrent Mode Failure失败,
此时虚拟机启动Serial Old收集器进行老年代垃圾回收停顿时间变长,性能降低。
【3】回收后空间碎片过多
因为CMS采用标记-清除算法因此回收后会产生大量空间碎片,无法给大对象分配连续内存空间而触发Full GC;
+UseCMSCompactAtFullCollection参数,用于在触发Full GC之前开启内存碎片整理过程,整理阶段不能并发,因此停顿时间加长。
-XX:CMSFullGCsBeforeCompaction参数,设置进行多少次不整理的Full GC之后,进行一次带整理的Full GC。
7,G1收集器
定义:一款面向服务端应用的垃圾收集器
算法:标记-整理
特点:
【1】并行与并发
充分利用多CPU,多核环境缩短Stop the World停顿时间,使用并发方式回收避免了GC时停顿java线程
【2】分代收集
【3】空间整合(使用了标记-整理回收算法,避免了大量空间内存碎片的产生)
【4】可预测的停顿(G1在追求低停顿同时建立了可预测的停顿时间模型,可以让使用者设置M毫秒内,GC所需要的时间不超过N毫秒)
原理:
1,G1将新生代和老年代分为大小相等的独立区域,进行全区域垃圾回收,新生代和老年代不再是物理隔离,都是部分独立区域的集合;
2,通过计算每个区域垃圾堆积的价值(回收可得到的空间/回收所需要的时间),然后根据价值大小有优先级地进行垃圾回收,保证了回收的效率;
3,虚拟机发现独立区域中的Reference类型数据进行写操作时,判断其他独立区域是否有Reference数据引用的对象(即老年代对象是否引用了新生代对象),
如果是就将引用信息通过CardTable记录到独立区域的Remembered Set中,在垃圾回收的时候将Remembered Set加入到GC根节点的枚举范围,可避免使用
可达性算法判断对象存活而进行的全堆扫描,也避免有存活对象的遗漏。
回收步骤:
【1】初始标记(标记GC Roots能直接关联到的对象,并修改TAMS(Next Top at Mark Start)的值,让下一阶段用户程序并发运行时,能在正确的Region中创建对象)(Stop the World)
【2】并发标记(从GC Roots开始对堆中对象可达性分析,找出存活对象)(和用户线程并发进行)
【3】最终标记(修正并发标记期间因用户线程运行的而产生变动对象的标记记录,虚拟机将这些对象记录到Remembered Set Logs中,然后合并到Rembered Set中)(Stop the World)
【4】筛选回收(对每个独立区域进行价值排序,根据用户期望的GC停顿时间制定回收计划)
四,回收器的使用
1,参数
UseSerialGC(使用Serial + Serial Old组合收集器)
UseParNewGC(使用ParNew + Serial Old组合收集器)
UseConcMarkSweepGC(使用ParNew + CMS + Serial Old组合收集器; Serial Old是CMS出现Concurrent Mode Failure失败后备用收集器)
UseParallelGC(使用Parallel Scavenge + Serial Old组合收集器)
UseParallelOldGC(使用Parallel Scavenge + Parallel Old组合回收器)
SurvivorRatio(新生代中Eden与Survivor容量比值; 默认是8,即Eden : Survivor = 8:1)
PretenureSizeThreshold(直接晋升到老年代对象的大小,超过此参数直接被分配在老年代)
MaxTenuringThreshold(晋升到老年代的对象年龄,每个对象Minor GC之后年龄+1, 超过此参数直接进入老年代)
UseAdaptiveSizePolicy(动态调整Java堆中个区域大小和进入老年代的年龄)
HandlePromotionFailure(是否允许担保分配失败,即老年代剩余空间不足应付新生代整个Eden和Survivor区所有对象都存活的极端情况)
ParallelGCThreads(设置并行GC回收时的线程数)
GCTimeRatio(GC时间占总时间比率,默认99,即允许1%的GC时间。 仅使用Parallel Scavenge收集器生效)
MaxGCPauseMillis(设置GC最大停顿时间。 仅使用Parallel Scavenge收集器生效)
CMSInitiatingOccupancyFraction(设置CMS在老年代空间被使用多少后触发一次GC, 默认68%, 仅使用CMS收集器生效)
UseCMSCompactAtFullCollection(设置CMS完成回收后是否要进行一次内存碎片整理, 仅使用CMS收集器生效)
CMSFullGCsBeforeCompaction(设置CMS在进行若干次回收后再启动一次内存碎片整理)
-XX:+PrintGCDetails(打印虚拟机日志)
2,回收器的组合使用
|
新生代
|
年老代
|
说明
|
组合1
|
Serial
|
Serial Old
|
都是单线程进行GC; GC时暂停所有应用线程
|
组合2
|
Serial
|
CMS+Serial Old
|
CMS是并发GC,和应用线程并发工作,不需要暂停所有应用线程
CMS出现Concurrent Mode Failure失败后使用Serial Old收集器
|
组合3
|
ParNew
|
CMS
|
用-XX:+UseParNewGC选项来开启
ParNew是Serial的并行版本,可以指定GC线程数,默认GC线程数为CPU的数量
使用-XX:ParallelGCThreads选项指定GC的线程数
用-XX:+UseConcMarkSweepGC选项,则新生代默认使用ParNew GC策略。
|
组合4
|
ParNew
|
Serial Old
|
用-XX:+UseParNewGC选项来开启
|
组合5
|
Parallel Scavenge
|
Serial Old
|
Parallel Scavenge策略主要是关注一个可控的吞吐量:应用程序运行时间 / (应用程序运行时间 + GC时间);
会使得CPU的利用率尽可能的高,适用于后台持久运行的应用程序,而不适用于交互较多的应用程序。
|
组合6
|
Parallel Scavenge
|
Parallel Old
|
Parallel Old是Serial Old的并行版本
|
组合7
|
G1
|
G1
|
-XX:+UnlockExperimentalVMOptions -XX:+UseG1GC 开启
-XX:MaxGCPauseMillis =50 暂停时间目标
-XX:GCPauseIntervalMillis =200 暂停间隔目标
-XX:+G1YoungGenSize=512m 年轻代大小
-XX:SurvivorRatio=6 新生代中Eden与Survivor容量比值
|
java虚拟机之GC(转)的更多相关文章
- java虚拟机(十三)--GC调优思路
GC调优对我们开发人员来说,如果你想要技术方面一直发展下去,这部分内容的了解是必不可少的,jvm对于工作.面试来说都很重要,GC调优的问题 更是重中之重,因为是对你jvm学习内容的实践,知识只有应用实 ...
- Java虚拟机之GC
⑴背景 Java堆和方法区实现类所需内存是不一样的,每个方法的多分支需要的内存也可能不一样,我们只有在运行期间才能制动创建哪些对象.这部分内存分配与回收都是动态的,而垃圾回收器所关注的就是这些这部分内 ...
- Java 虚拟机枚举 GC Roots 解析
JVM 堆内存模型镇楼. 读<深入理解 Java 虚拟机>第三章GC算法,关于 GC Roots 枚举的段落没说透彻,理解上遇到困惑.因此对这点进行扩展并记录,发现国内各种博客写来写去都是 ...
- java虚拟机(十一)--GC日志分析
GC相关:java虚拟机(六)--垃圾收集器和内存分配策略 java虚拟机(五)--垃圾回收机制GC 打印日志相关参数: -XX:+PrintGCDetails -XX:PrintGCTimestam ...
- 深入理解java虚拟机,GC参考手册
深入理解java虚拟机 一.<深入理解Java虚拟机> 1.第2章 Java内存区域与内存溢出异常 2.第3章 垃圾收集器与内存分配策略 3.第4章 虚拟机性能监控与故障处理工具 4.第5 ...
- Java虚拟机:GC算法深度解析
版权声明:本文为博主原创文章,转载请注明出处,欢迎交流学习! 在前面的文章里介绍了可达性分析算法,它为我们解决了判定哪些对象可以回收的问题,接下来就该我们的垃圾收集算法出场了.不同的垃圾收集算法有各自 ...
- 深入理解Java虚拟机,gc输出参数
https://blog.csdn.net/qq_21383435/article/details/80702205
- java虚拟机(十二)--可视化工具分析GC日志
在上篇博客中,我们学习了Parallel.CMS.G1三种垃圾收集器的日志格式,本次我们通过工具去分析日志,会更加的直观 日志格式博客地址:java虚拟机(十一)--GC日志分析 GCeasy: 这是 ...
- Java虚拟机-垃圾收集器
垃圾收集器(Garbage Collection, GC)的诞生引导出了三个问题: 哪些内存需要回收? 什么时候回收? 如何回收? 对于线程独占的三个区域(程序计数器.虚拟机栈.本地方法栈)不用过多的 ...
随机推荐
- JavaScript高级知识点整理
一.JS中的数组 1.数组的三种定义方式 (1).实例化对象 var aArray=new Array(1,2,3,4,5); (2).快捷创建 var aTwoArray = [1,2,3,&quo ...
- Java性能优化之高性能JAVA代码的若干个习惯
创建对象: 1.避免在循环体中创建对象,循环前应该创建对象,避免浪费更多内存空间和增加GC负担 这种情况在我们的实际应用中经常遇到,而且我们很容易犯类似的错误,例如下面的代码: for (int i ...
- spoj Longest Common Substring
Longest Common Substring SPOJ - LCS 题意:求两个串的最长公共子串 /* 对一个串建立后缀自动机,用另一个串上去匹配 */ #include<iostream& ...
- jdk 1.6.0_41 下载
Java SE Development Kit 6u41 Product / File Description File Size Download password Linux x86 65.43 ...
- Leetcode 283. Move Zeroes 移动数组中的零 (数组,模拟)
题目描述 已知数组nums,写一个函数将nums中的0移动到数组后面,同时保持非零元素的相对位置不变.比如已知nums=[0,1,0,3,12],调用你写的函数后nums应该是[1,3,12,0,0] ...
- 关于nginx限速的配置
limit_req zone=req_one burst=; zone定义了一个req_one的name,burst表示允许超过限制的请求数不多于20个,后面可加参数(nodelay):超过的请求不会 ...
- pytorch 加载mnist数据集报错not gzip file
利用pytorch加载mnist数据集的代码如下 import torchvision import torchvision.transforms as transforms from torch.u ...
- git学习--clone和pull
clone:从远程服务器克隆一个一模一样的版本库到本地,复制的是整个版本库.(clone是将一个库复制到你的本地,是一个本地从无到有的过程) pull:从远程服务器获取到一个branch分支的更新到本 ...
- sql CET实现循环
表结构 CREATE TABLE city( id INT IDENTITY(1,1) PRIMARY KEY, NAME NVARCHAR(100), ParentID INT , Parents ...
- shell 获取hive表结构
hive -S -e "select * from db_name.table_name limit 0"|grep table_name|xargs -n1|sed 's/tab ...