JVM:垃圾回收机制和调优手段
转载请注明出处: jiq•钦's technical Blog - 季义钦
引言:
我们都知道JVM内存由几个部分组成:堆、方法区、栈、程序计数器、本地方法栈
JVM垃圾回收仅针对公共内存区域即:堆和方法区进行,由于仅仅有这两个区域在执行时才干知道须要创建哪些对象,其内存分配和回收都是动态的。
本文主要讨论两点,一是垃圾回收策略,二是调优的方法。
一、垃圾回收机制
1.1 分代管理
将堆和方法区依照对象不同年龄进行分代:
u 堆中会频繁创建对象,基于一种分代的思想,依照对象存活时间将堆划分为新生代和旧生代两部分。我们不能一次垃圾回收新生代存活的对象就放入旧生代,而是要经过几次GC后还存活的对象,我们才放入旧生代,所以我们又把新生代再次划分为Eden区和两个Survivor区,让对象创建在Eden区,然后在两个Survivor之间重复复制,最后仍然存活的对象才拷贝到旧生代中。
u 方法区存放的是常量、载入的字节码文件信息等,信息相对稳定。
由于不会频繁创建对象,所以不须要分代,直接GC就可以。
由此我们JVM垃圾回收要扫描的范围是:
注:图片来自网络
新生代:
1. 全部新对象创建发生在Eden区。Eden区满后触发新生代上的minor GC,将Eden区和非空暇Survivor区存活对象拷贝到还有一个空暇的Survivor区中。
2. 永远保证一个Survivor是空的,新生代minor GC就是在两个Survivor区之间相互复制存活对象,直到Survivor区满为止。
旧生代:
1. Eden区满后触发minor GC将存活对象拷贝到Survivor区,Survivor区满后触发minor GC将存活对象拷贝到旧生代。
2. 经过新生代的两个Survivor之间多次复制,仍然存活下来的对象就是年龄相对照较老的。就能够放入到旧生代了。随着时间推移。假设旧生代也满了。将触发Full GC,针对整个堆(包含新生代、旧生代和持久代)进行垃圾回收。
持久代:
持久代假设满,将触发Full GC
1.2 垃圾回收
要执行gc关键在于两点,一是检測出垃圾对象,二是释放垃圾对象所占用的空间。
1.2.1 检測垃圾对象
检測出垃圾对象一般有两种算法:
1、 引用计数法
2、 可达性分析
引用计数法由于无法检測对象之间相互循环引用的问题,基本没有被採用。如今主流的语言的垃圾收集中检測垃圾对象主要还是“可达性分析”方法。以下也主要介绍JVM可达性分析方法检測垃圾对象。
“可达性分析”算法描写叙述?
通过一系列的名为“GC Root”的对象作为起点,从这些节点向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Root没有不论什么引用链相连时,则该对象不可达。该对象是不可使用的。垃圾收集器将回收其所占的内存。所以JVM推断对象须要存活的原则是:能够被一个根对象到达的对象。
什么是能够到达呢?
就是对象A中引用了对象B,那么就称A到B可达。
GCRoot对象集合?
a. java虚拟机栈(栈帧中的本地变量表)中的引用的对象。(当前栈帧的对象引用)
b.方法区中的类静态属性引用的对象。(static对象引用)
c.方法区中的常量引用的对象。(final对象引用)
d.本地方法栈中JNI本地方法的引用对象。
除了堆之外,方法区也须要进行垃圾回收GC,那么怎样检測出方法区的垃圾对象呢?
方法区中的“废弃常量”和“没用的类”须要回收以保证永久代不会发生内存溢出。
1、推断废弃常量的方法(常量不再须要):假设常量池中的某个常量没有被不论什么引用所引用,则该常量是废弃常量。
2、推断没用的类(class文件不再须要):
(1).该类的全部实例都已经被回收,即java堆中不存在该类的实例对象。
(2).载入该类的类载入器已经被回收。
(3).该类所相应的java.lang.Class对象没有不论什么地方被引用。无法在不论什么地方通过反射机制訪问该类的方法。
当持久代(方法区)满时,将触发Full GC,依据以上标准清除掉废弃的常量和没用的类。
1.2.2 释放空间
1、垃圾回收算法
前面已经介绍了怎样检測出垃圾对象,在检測出垃圾对象之后,须要依照特定的垃圾回收算法进行内存回收,常见的垃圾回收算法包含:
u 复制(Copying)
u 标记-清除(Mark-Sweep)
u 标记-整理(Mark-Compact)
u 分代(Generational Collection),借助前面三种算法实现
这里就不一一详述,感兴趣能够自行百度。
2、垃圾收集器实现
上面算法都是理论性的东西,Java虚拟机规范没有规定垃圾收集器具体怎样实现,因此不同厂商、不同版本号虚拟机提供的垃圾收集器可能有所差异。
以下列举HotSpot(Sun JDK和Open JDK自带)虚拟机提供的六种垃圾收集器实现:
收集器名称 |
应用目标 |
採用算法 |
引入版本号 |
执行方式 |
Serial |
新生代 |
复制算法 |
Jdk1.3.1前 |
串行,单线程 |
ParNew |
新生代 |
复制算法 |
|
并行,多线程 |
Parallel Scavenge |
新生代 |
复制算法 |
Jdk1.4 |
并行。多线程 |
Serial Old |
旧生代 |
标记-整理 |
|
串行,单线程 |
Parallel Old |
旧生代 |
标记-整理 |
Jdk1.6 |
并行,多线程 |
CMS |
旧生代 |
标记-清除 |
Jdk1.5 |
并发。多线程 |
并行(Parallel):多条垃圾收集线程并行工作,而用户线程仍处于等待状态
并发(Concurrent):垃圾收集线程与用户线程一段时间内同一时候工作(不是并行,而是交替执行)
总结:
1、 两个串行收集器、三个并行收集器、一个并发收集器。
2、 ParNew收集器是Serial的多线程版本号
3、 Serial Old收集器是Serial收集器的旧生代版本号。
4、 Parallel Scavenge收集器以吞吐量为目标,适合在后台运算而不须要太多交互的任务。
5、 Parallel Old收集器是Parallel Scavenge的旧生代版本号。
6、 Parallel Scavenge收集器和Parallel Old收集器是名副事实上的“吞吐量优先”组合。
7、 除CMS外,其它收集器工作时都须要暂停其它全部线程,CMS是第一款真正意义上的并发(Concurrent)收集器,第一次实现了让垃圾收集器线程与用户线程同一时候工作,是一款以最短停顿时间为目标的收集器。适合交互性较多的场景,这也是与Parallel Scavenge/Parallel Old吞吐量优先组合的差别。
8、 新生代由于回收留下的对象少,所以採用标记-复制法。
9、 旧生代由于回收留下的对象多,所以採用标记-清除/标记-整理算法。
3、选择所需垃圾收集器
虚拟机提供了參数,以便用户依据自己的需求设置所需的垃圾收集器:
JVM执行參数 |
新生代 |
旧生代 |
-XX:+UseSerialGC(Client模式默认值) |
Serial |
Serial Old |
-XX:+UseParNewGC |
ParNew |
Serial Old |
-XX:+UseConcMarkSweepGC |
ParNew |
CMS(Serial Old备用) |
-XX:+UseParallelGC(Server模式默认值) |
Parallel Scavenge |
Serial Old |
-XX:+UseParallelOldGC |
Parallel Scavenge |
Parallel Old |
二、性能调优
2.1 性能调优的目的
降低minor gc的频率、以及full gc的次数
2.2 性能调优的手段
1.使用JDK提供的内存查看工具。如JConsole和Java VisualVM
2.控制堆内存各个部分所占的比例
3.採用合适的垃圾收集器
手段1:内存查看工具(如jstat)和GC日志分析
n -verbose.gc:显示GC的操作内容。打开它,能够显示最忙和最空暇收集行为发生的时间、收集前后的内存大小、收集须要的时间等。
n -xx:+printGCdetails:具体了解GC中的变化。
n -XX:+PrintGCTimeStamps:了解这些垃圾收集发生的时间。自JVM启动以后以秒计量。
n -xx:+PrintHeapAtGC:了解堆的更具体的信息。
此外还包含通过jmap+MAT的方式分析可能发生的内存泄露的原因,哪些对象占用内存较大等。
手段2:针对新生代和旧生代的比例
假设新生代太小,会导致频繁GC。并且大对象对直接进入旧生代引发full gc
假设新生代太大,会诱发旧生代full gc,并且新生代的gc耗时会延长
建议新生代占整个堆1/3合适,相关JVM參数例如以下:
n -Xms:初始堆大小
n -Xmx:最大堆大小
n - Xmn:新生代大小
n -XX:PermSize=n:持久代最大值
n -XX:MaxPermSize=n:持久代最大值
n -XX:NewRatio=n:设置新生代和旧生代的比值。如:为3。表示新生代与旧生代比值为1:3,新生代占整个新生代旧生代和的1/4
手段3:针对Eden和Survivor的比例
假设Eden太小。会导致频繁GC
假设Eden太大,会导致大对象直接进入旧生代。降低对象在新生代存活时间
n -XX:SurvivorRatio=n:新生代中Eden区与两个Survivor区的比值。注意Survivor区有两个。如:3,表示Eden:Survivor=3:2。一个Survivor区占整个年轻代的1/5
n -XX:PretenureSizeThreshold:直接进入旧生代中的对象大小。设置此值后,大于这个參数的对象将直接在旧生代中进行内存分配。
n -XX:MaxTenuringThreshold:对象转移到旧生代中的年龄,每一个对象经历过一次新生代GC(Minor GC)后,年龄就加1,到超过设置的值后。对象转移到旧生代。
手段4:採用正确的垃圾收集器
通过JVM參数设置所使用的垃圾收集器參考前面的介绍,这里关注其它一些设置。
并行收集器设置
n -XX:ParallelGCThreads=n:设置并行收集器收集时并行收集线程数
n -XX:MaxGCPauseMillis=n:设置并行收集最大暂停时间,仅对ParallelScavenge生效
n -XX:GCTimeRatio=n:设置垃圾回收时间占程序执行时间的百分比。仅对Parallel Scavenge生效
并发收集器设置
n -XX:CMSInitiatingOccupancyFraction:默认设置下。CMS收集器在旧生代使用了68%的空间后就会被激活。此參数就是设置旧生代空间被使用多少后触发垃圾收集。注意要是CMS执行期间预留的内存无法满足程序须要。就会出现concurrent mode failure,这时候就会启用Serial Old收集器作为备用进行旧生代的垃圾收集。
n -XX:+UseCMSCompactAtFullCollection:空间碎片过多是标记-清除算法的弊端。此參数设置在FULL GC后再进行一个碎片整理过程
n -XX:CMSFullGCsBeforeCompaction:设置在若干次垃圾收集之后再启动一次内存碎片整理
JVM:垃圾回收机制和调优手段的更多相关文章
- JVM垃圾回收机制总结:调优方法
转载: JVM垃圾回收机制总结:调优方法 JVM 优化经验总结 JVM 垃圾回收器工作原理及使用实例介绍
- ☕【JVM技术指南】「JVM总结笔记」Java虚拟机垃圾回收认知和调优的"思南(司南)"【下部】
承接上文 (完结撒花1-52系列)[JVM技术指南]「JVM总结笔记」Java虚拟机垃圾回收认知和调优的"思南(司南)"[上部] 并行收集器 并行收集器(也称为吞吐量收集器)是类似 ...
- JVM内存管理、JVM垃圾回收机制、新生代、老年代以及永久代
内存模型 JVM运行时数据区由程序计数器.堆.虚拟机栈.本地方法栈.方法区部分组成,结构图如下所示. JVM内存结构由程序计数器.堆.栈.本地方法栈.方法区等部分组成,结构图如下所示: 1)程序计数器 ...
- JVM内存管理和JVM垃圾回收机制
JVM内存管理和JVM垃圾回收机制(1) 这里向大家描述一下JVM学习笔记之JVM内存管理和JVM垃圾回收的概念,JVM内存结构由堆.栈.本地方法栈.方法区等部分组成,另外JVM分别对新生代和旧生代采 ...
- JVM垃圾回收机制概述
JVM垃圾回收机制概述 1.定义 是指JVM用于释放那些不再使用的对象所占用的内存. 2.方式 2.1引用计数(早期) 当引用程序创建引用以及引用超出范围时,JVM必须适当增减引用数.当某个对象的引用 ...
- Java虚拟机学习笔记——JVM垃圾回收机制
Java虚拟机学习笔记——JVM垃圾回收机制 Java垃圾回收基于虚拟机的自动内存管理机制,我们不需要为每一个对象进行释放内存,不容易发生内存泄漏和内存溢出问题. 但是自动内存管理机制不是万能药,我们 ...
- JVM基础系列第8讲:JVM 垃圾回收机制
在第 6 讲中我们说到 Java 虚拟机的内存结构,提到了这部分的规范其实是由<Java 虚拟机规范>指定的,每个 Java 虚拟机可能都有不同的实现.其实涉及到 Java 虚拟机的内存, ...
- JVM 垃圾回收机制和常见算法和 JVM 的内存结构和内存分配(面试题)
一.JVM 垃圾回收机制和常见算法 Sun 公司只定义了垃圾回收机制规则而不局限于其实现算法,因此不同厂商生产的虚拟机采用的算法也不尽相同.GC(Garbage Collector)在回收对象前首先必 ...
- JVM垃圾回收机制和常用算法
由于疫情的原因,所以目前一直在家远程办公,所以很多时间在刷面试题,发现2019大厂的面试虽然种类很多,但是总结了一下发现主要是这几点:算法和数据结构. JVM.集合.多线程.数据库这几点在面试的时候比 ...
随机推荐
- Tasker App Factory
http://tasker.dinglisch.net/userguide/en/appcreation.html App Creation Introduction Hello World Exam ...
- 我对NHibernate的感受(1):对延迟加载方式的误解
NHibernate是.NET平台上最著名的ORM框架,虽说出身于Java平台上的Hibernate,但是从外部看来这几乎就是一个.NET平台上的原生产品:有自己的社区,有自己的用户,有自己的商业支持 ...
- BitmapFactory.Options.inSampleSize 的使用方法
BitmapFactory.decodeFile(imageFile); 用BitmapFactory解码一张图片时.有时会遇到该错误. 这往往是因为图片过大造成的. 要想正常使用,则须要分配更少的内 ...
- IOC详解和Unity基础使用介绍
说起IOC,可能很多初学者不知道是用来做什么的,今天正好有点时间,就来扫扫盲,顺便巩固下自己. IOC全称是Inversion Of Control,意为控制反转(这些自然百度也有),可什么是控制反转 ...
- 视图Ext.Viewport和窗口Ext.Window用法
Viewport不需要再指定renderTo,而我们也看到Viewport确实填充了整个浏览器显示区域,并会随着浏览器显示区域大小的改变而改改.他有三个特点: 1).创建即可使用.不需要渲染,当组件在 ...
- unity 质量设置 Quality Settings
Unity allows you to set the level of graphical quality it will attempt to render. Generally speaking ...
- struts2 <s:select>标记取包含map的list的值
如下list map.put("ID","001"); map.put ("NM","test1"); list.add ...
- C++常用排序法、随机数
C++常用排序法研究 2008-12-25 14:38 首先介绍一个计算时间差的函数,它在<time.h>头文件中定义,于是我们只需这样定义2个变量,再相减就可以计算时间差了. 函数开头加 ...
- strstr实现
// strstr.c查找完全匹配的子字符串 #include<stdio.h> #include<string.h> char *my_strstr(const char * ...
- 【BZOJ】【2752】【HAOI2012】高速公路(Road)
数学期望/线段树 然而又是一道road= =上一道是2750…… 下次不要一看期望题就弃疗么…… 期望题≠不可做题……!! 其实在这题中,期望就是(所有情况下 权值之和)/(总方案数) 因为是等概率抽 ...