JVM垃圾回收器、内存分配与回收策略
1. Serial收集器
serial收集器即串行收集器,是一个单线程收集器。
串行收集器在进行垃圾回收时只使用一个CPU或一条收集线程去完成垃圾回收工作,并且会暂停其他的工作线程(stop the world),直至回收完成。适用于运行在client模式下的JVM。
在单CPU年代,串行收集器是默认的垃圾回收器,minor GC和major GC的过程都是用一个线程去处理的。
启用方式:-XX: +UseSerialGC
2. ParNew收集器
parNew收集器即并行收集器,采用的是多线程方式进行垃圾回收,可以理解为Serial收集器的多线程版本,吞吐量要比串行高很多,是服务器级别的虚拟机默认使用的,用来处理新生代的垃圾回收器。
因为采用的是并行多线程方式,建议在多CPU环境下使用,否则和Serial没有区别。
启用方式:-XX: +UseParNewGC
3. Parallel Scavenge收集器
并行的多线程垃圾收集器,采用复制算法进行垃圾回收,非常适合服务器做计算任务时使用。
一般的垃圾回收器是在尽量短的时间内进行垃圾回收,这样程序与用户交互的时间间隔比较小,不会出现长时间的卡顿现象。但是Parallel Scavenge更侧重于系统的吞吐量,高效的利用CPU,优先处理计算任务,适合交互少、运算多的场景。
通过参数-XX: MaxGcPauseMills设置GC最大停顿时间,通过参数-XX: GCTimeRatio设置吞吐量大小。
启用方式:-XX: +UseParallelGC
老年代垃圾收集器
1. Serial Old收集器
serial收集器的老年代版本,同样是单线程收集器、stop the world,使用标记整理算法。一般启用方式:UseSerialGC是Serial + Serial OldUseParNewGC是ParNew + Serial OldUseParallelGC是Parallel Scavenge + Serial Old
2. Parallel Old收集器
老年代版本的Parallel Scavenge,使用多线程 + 标记整理算法。启用方式:-XX: +UseParallelOldGC
3. CMS垃圾收集器
CMS收集器的主要目的是使垃圾回收造成的停顿时间最短,提高服务响应速度,使用标记清除算法,具有并发收集(用户线程与垃圾收集并发执行)、低停顿的特点。运行过程分为以下四个步骤:
1. 初始标记:stop the world,只是标记一下GC Roots能直接关联到的对象,速度快
2. 并发标记:进行GC RootsTracing过程
3. 重新标记:stop the world,修正并发标记期间因用户程序继续运行而导致的标记产生变动的那部分对象的标记记录。这个阶段停顿时间相对初始标记时间长,比并发标记时间短
4. 并发清除注意:
- CMS收集器对CPU资源敏感,这是面向并发程序设计的共性
- 无法处理浮动垃圾(CMS垃圾收集阶段,用户线程仍在运行,因此会有新的垃圾生成,这部分垃圾只能在下一次GC时再清理,即浮动垃圾),可能出现"Concurrent Mode Failure"失败导致另一次full GC
启用方式:-XX:+UseConcMarkSweepGC
G1收集器
G1收集器是基于标记整理算法实现的收集器,所以它不会产生内存空间碎片,并且可以精确的控制停顿时间。能让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒。
G1的设计原则就是简单可行的性能调优,只需声明以下参数即可:
-XX:+UseG1GC -Xmx16g -XX:MaxGCPauseMills=300
其中,-XX:+UseG1GC表明开启G1收集器,-Xmx16g设置堆内存为16g,-XX:MaxGCPauseMills=300设置GC停顿最大时间为300ms。如果我们需要调优,在内存一定的情况下,可以考虑修改该参数,当然还要根据实际业务场景来处理。
G1取消了堆内结构的新生代、老年代的物理空间划分,将整个Java堆划分为大小固定的独立区域,后台维护一个优先列表来跟踪这些区域的垃圾堆积程度,每次根据允许收集的时间,优先回收垃圾最多的区域。
G1中的Humongous区域用于存储生命周期较短的巨型对象(一个对象所占空间超过了分区容量的50%),如果一个Humongous区无法装下一个巨型对象,G1会寻找连续的H分区来存储,如果没有连续的H区满足这种情况,有时候会触发full GC。
G1收集器的运作主要划分为以下四个步骤:
- 初始标记:标记GC Roots能直接关联到的对象,需要停顿线程,但耗时很短
- 并发标记:从GC Roots开始对堆中对象进行可达性分析,找出存活的对象,这阶段耗时较长,但可与用户程序并发执行
- 最终标记:修正在并发标记期间因用户程序继续运作而导致标记产生变动的那一部分标记记录
- 筛选回收:对各个Region的回收价值和成本进行排序,根据用户所期望的GC停顿时间来制定回收计划
内存分配与回收策略
对象的内存分配主要是指在Java堆上的分配,通常会优先分配在新生代,然后经历一系列GC后仍然存活的对象会进入到老年代。少数情况下,一些对象也会直接进入到老年代。
-Xms:设置初始化堆内存,-Xmx设置最大堆内存,设置为相等可防止内存抖动(剩余内存大于70%、小于40%时,自动触发内存扩大或缩小)
1. 对象会优先分配在新生代
新生代划分为一个eden区和两个survivor区(from survivor、to survivor)。初始阶段,新创建的对象会分配给eden区。新生代发生的GC成为minor GC即Young GC,主要分为以下几个过程:
- 随着eden区存储的对象不断增多,当eden区剩余空间无法存储新生成的对象时会触发GC
- 经过minor GC后仍然存活的对象会进入from survivor区
- 当再次触发GC时,会扫描eden区和from survivor区,对这两个区域进行垃圾回收,仍然存活的对象会被复制到to survivor区,同时这些存活的对象年龄加1
- 清空eden、from survivor区中的对象,并将from survivor和to survivor区互换
- 频繁执行上述过程,当剩余存活对象年龄达到15(默认)时,这些对象会进入老年代,通过参数-XX:MaxTenuringThreshold控制
-Xmn用来设置新生代大小,一般设置为整个堆内存的3/1或者1/4
-XX:NewRatio设置新生代与老年代的堆内存比例
-XX:SurvivorRatio设置eden区和survivor区之间的比例
2. 老年代存储的对象
发生在老年代的GC是major GC,回收速度会比minor GC慢。
上文已经说明了对象进入老年代的一种情况即长期存活的对象会进入老年代,这里再来看看其他情况:
1. 大对象直接进入老年代大对象需要的连续存储空间(如数组)大于新生代剩余空间时,会直接进入老年代。
通过参数-XX:PretenureSizeThreshold设置,大于该参数值的对象会直接进入老年代(避免新生代中大量对象的拷贝,效率低)
注意:PretenureSizeThreshold参数只对部分垃圾回收器有效,比如Serial和ParNew
2. 如果survivor区相同年龄所有对象大小的总和大于survivor空间的一半,年龄大于或等于该年龄的对象可以直接进入老年代,无需等到MaxTenuringThreshold设置的年龄
注意:永久代不属于堆空间,通过参数-XX:PermSize,-XX:MaxPermSize控制大小
3. Full GC
full GC是针对整个Java堆空间进行垃圾回收,包括新生代和老年代,会造成stop world。要尽量避免full GC,它会影响程序的稳定性。
导致Full GC的几点原因:
1. 老年代空间不足从年轻代进入老年代的对象所占空间大于老年代剩余空间大小。eden区调大一些,尽量让对象在新生代minor GC回收,而不是集中在老年代进行major GC,尽量不要创建特别大的对象
2. 垃圾回收算法用的不对比如在老年代使用复制收集算法
3. 永久代空间不足
4. 被HandlePromotionFailure参数强制Full GC
在发生minor GC时,虚拟机会检测之前每次晋升到老年代的平均大小是否大于老年代的剩余空间大小,如果大于,则改为进行full GC。如果小于,则根据HandlePromotionFailure的设置是否允许担保分配内存失败:如果允许失败,则只进行minor GC;反之,则进行full GC。
但是如果发生HandlePromotionFailure失败,则会进行full GC。
关注微信公众号:大数据学习与分享,获取更对技术干货
JVM垃圾回收器、内存分配与回收策略的更多相关文章
- JVM探秘:内存分配与回收策略
本系列笔记主要基于<深入理解Java虚拟机:JVM高级特性与最佳实践 第2版>,是这本书的读书笔记. 内存分配一般关注的是对象在堆上分配的情况,对象主要分配在新生代的Eden区中,如果启用 ...
- Java虚拟机垃圾回收:内存分配与回收策略 方法区垃圾回收 以及 JVM垃圾回收的调优方法
在<Java对象在Java虚拟机中的创建过程>了解到对象创建的内存分配,在<Java内存区域 JVM运行时数据区>中了解到各数据区有些什么特点.以及相关参数的调整,在<J ...
- JVM学习十 -(复习)内存分配与回收策略
内存分配与回收策略 对象的内存分配,就是在堆上分配(也可能经过 JIT 编译后被拆散为标量类型并间接在栈上分配),对象主要分配在新生代的 Eden 区上,少数情况下可能直接分配在老年代,分配规则不固定 ...
- Java虚拟机内存分配与回收策略
内存分配与回收策略 Minor GC 和 Full GC Minor GC:发生在新生代上,因为新生代对象存活时间很短,因此 Minor GC 会频繁执行, 执行的速度一般也会比较快. Full GC ...
- jvm内存分配和回收策略
在上一篇中,已经介绍了内存结构是什么样的. 这篇来介绍一下 内存是怎么分配的,和怎么回收的.(基本取自<深入理解Java虚拟机>一书) java技术体系中所提倡的自动内存管理最终可以归结为 ...
- JVM的内存分配和回收策略
对象的Class加载 虚拟机遇到一条new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载.解析和初始化过.如果没有,那必须先执行相应 ...
- JVM 内存分配和回收策略
对象的内存分配,主要是在java堆上分配(有可能经过JIT编译后被拆为标量类型并间接地在栈上分配),如果启动了本地线程分配缓冲,将按线程优先在TLAB上分配.少数情况下也是直接分配到老年代,分配规则不 ...
- JVM:内存分配与回收策略
Java技术体系中所提倡的自动内存管理最终可以归结为自动化的解决了两个问题:给对象分配内存以及回收分配给对象的内存. 对象的内存分配,往大方向讲,就是在堆上分配(但也可能经过JIT编译后被拆散为标量类 ...
- A4. JVM 内存分配及回收策略
[概述] Java 技术体系中所提倡的自动内存管理最终可以归结为自动化地解决两个问题:给对象分配内存以及回收分配给对象的内存. 对象的内存分配,往大方向讲,就是在堆上分配,对象主要分配在新生代的 Ed ...
随机推荐
- 【总结】IP
一. IP基本认识 1.IP 在 TCP/IP 参考模型中处于第三层,也就是网络层. 网络层的主要作用是:实现主机与主机之间的通信,也叫点对点(end to end)通信 2.网络层与数据链路层有什么 ...
- Spring 5的最后一个特性版本5.3发布,4.3将于12月终止维护
10月27日,Spring Framework团队宣布了5.3版本正式GA,Spring用户可以在repo.spring.io和Maven Central上获取到最新版本的依赖包. JDK的版本支持 ...
- 购买GPRS DTU时应该怎么选择
GPRS DTU如今是一种被广泛应用的物联网无线数据终端,主要是利用GPRS网络为用户提供无线长距离数据透传功能,在电力.环保.物流.气象等行业领域有着广泛应用.目前市场上的GPRS DTU产品眼花缭 ...
- 一个.NET Core下的开源插件框架
插件模式历史悠久,各种中大型软件基本上都会实现插件机制,以此支持功能扩展,从开发部署层面,插件机制也可实现功能解耦,对于并行开发.项目部署.功能定制等都有比较大的优势. 在.NET Core下,一般我 ...
- uniapp微信小程序获取当前用户手机号码(前端)
按钮触发获取用户信息 uniapp中与微信小程序官网所写会不同, <button open-type="getPhoneNumber" @getphonenumber=&qu ...
- 浅谈MVP
MVP是什么 MVP:Model-View-PresenterModel:表示数据提供者:View:表示数据展示:Presenter:是M与V沟通的桥梁. MVP工作方式 UI:告知Presenter ...
- Git命令之diff
工作区(working tree),暂存区(index /stage),本地仓库(repository) git跟不同的参数,比较不同的区间的版本. git diff:是查看working tree与 ...
- Simulink中封装子系统
学习目的: 使用simulink封装一个子系统,并将封装子系统放入到自定义的库中,可供建模时重复使用 功能:封装一个能够检测输入信号下降沿跳变的边沿检测模块,该模块可支持双击时修改内部参数.封装完成后 ...
- 内网渗透 day14-empire基础命令的使用
empire的基础操作 目录 1. 建立监听器 2. 设置stagers 3. 用户交互 4. 提权 1. 建立监听器 help 查看帮助命令 listeners 查看监听器 useli ...
- 中介者模式及在NetCore中的使用MediatR来实现
在现实生活中,常常会出现好多对象之间存在复杂的交互关系,这种交互关系常常是"网状结构",它要求每个对象都必须知道它需要交互的对象.例如,每个人必须记住他(她)所有朋友的电话:而且, ...