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 ...
随机推荐
- conda回滚
1. 查看历史版本: conda list --revision 2. 安装上次版本: conda install revision 13 13是历史序号.从上面看出,最近的历史序号是14,因此上一个 ...
- jmeter 使用总结
安装和启动(mac) 下载jmeter安装包并解压,进入其bin目录,执行./jmeter.sh或sh jmeter,打开就会出现如下画面 Thread Group 新建线程组,如下图 需要设置的选项 ...
- Java安全之安全加密算法
Java安全之安全加密算法 0x00 前言 本篇文来谈谈关于常见的一些加密算法,其实在此之前,对算法的了解并不是太多.了解的层次只是基于加密算法的一些应用上.也来浅谈一下加密算法在安全领域中的作用.写 ...
- C# stopwatch的简单使用(计算程序执行时间)
首先添加引用 using System.Diagnostics;//stopwatch的引用 //声明变量 Stopwatch a=new Stopwatch();//PS:这里一定要new(实例化) ...
- SDOI征途--斜率优化
题目描述 给定长为 n 的数列 a, 要求划分成 m 段,使得方差最小, 输出方差\(*m^2\) 题解 斜率优化好题 准备部分 设第 i 段长为 \(len_i\) 先考虑方差(\(S^2\))的式 ...
- 1. Spark Word Count
1. request: 2. scala: sc.textFile("input").flatMap(_.split(" ")).map((_,1)).redu ...
- svg究竟是什么?
svg究竟是什么? 1 要点 要点1:svg与jpg/png等格式的用途完全不同,不可相提并论,没有可比性,不可互相替代. 要点2:日常生活中,我们用相机拍摄自然景象得到的照片和视频,能且只能用jpg ...
- apache+php安装
https://codebriefly.com/how-to-setup-apache-php-mysql-on-windows-10/ 出问题的地方 1.apache rewrite 模块开启 (去 ...
- LR-demo
from __future__ import print_function # 导入相关python库 import os import numpy as np import pandas as ...
- C++实现管理系统
概述 系统中需要实现的功能如下: 添加联系人:向通讯录中添加新人,信息包括(姓名.性别.年龄.联系电话.家庭住址)最多记录1000人 显示联系人:显示通讯录中所有的联系人信息 删除联系人:按照姓名进行 ...