JVM内存模型与垃圾回收

JVM结构

1. JVM可划分为:堆、方法区、程序计数器、本地方法栈、虚拟机栈(栈)

	线程共享区域:堆、方法区
	
	线程私有区域:程序计数器、本地方法栈、栈

2. 各个区域的作用和存放类型

	1)程序计数器
	
		当前线程执行的字节码的行号指示器,记录指令执行的位置
		
	2)虚拟机栈:基本数据类型值、对象引用、方法调用
	
		为方法执行服务,每次调用方法都会创建方法栈,如果递归没有终止条件,则会造成StackOverFlow(SOF)
	
		每个方法执行会创建一个栈,存储局部变量、操作栈、动态链接等
		
	3)本地方法栈
	
		本地方法栈是为Native方法服务
	
	4)堆:主要存储对象和数组
	
	5)方法区
	
		存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据
		
	6)运行时常量池(方法区一部分)
	
		属于方法区一部分,用于存放编译期生成的各种字面量和符号引用
		
		编译器和运行期(String 的 intern())都可以将常量放入池中
		
	7)永久代
		
		是hotspot独有的方法区的一种实现,在1.8被metaspace(元空间)取代,元空间使用的是本地内存

		元空间的大小仅受本地内存限制,但可以通过以下参数来指定元空间的大小:

		-XX:MetaspaceSize,初始空间大小,达到该值就会触发垃圾收集进行类型卸载,同时GC会对该值进行调整:如果释放了大量的空间,就适当降低该值;如果释放了很少的空间,那么在不超过MaxMetaspaceSize时,适当提高该值。 
		-XX:MaxMetaspaceSize,最大空间,默认是没有限制的。

		除了上面两个指定大小的选项以外,还有两个与 GC 相关的属性: 
		-XX:MinMetaspaceFreeRatio,在GC之后,最小的Metaspace剩余空间容量的百分比,减少为分配空间所导致的垃圾收集 
		-XX:MaxMetaspaceFreeRatio,在GC之后,最大的Metaspace剩余空间容量的百分比,减少为释放空间所导致的垃圾收集

堆的内存模型

1. 堆主要分为:新生代(young)和老年代(old)

2. 新生代:存放新创建的对象,一般占据1/3的堆内存

	新生代又分为:Eden区、survivor from、survivor to
	
	Eden区:用于存放新创建的对象的区域
	
	survivor from:也叫survivor0区,存放上一次GC后留下的对象
	
	survivor to:也叫survivor1区,用于存放MinorGC时存活的对象
	
	Eden : survivor from : survivor to = 8 : 1 : 1

3. 老年代:存放生命周期较长的对象,多次GC未被回收的对象

垃圾回收算法

1. 标记清除:Mark and Sweap

	1)标记:标记所有和GCRoots可达的对象
	
	2)清除:遍历堆,将没有标记的对象进行清除
		
	缺点:需要对整块内存进行遍历,效率低,并且内存碎片化比较严重,影响存放效率(增加寻址时间)

2. 复制算法:Copy And Sweap

	1)Copy:使用2块内存空间,当其中一块内存存满后,将这块内存的存活对象(可达对象)复制到另一块内存
	
	2)Sweap:然后将内存全部清除,这样就达到了回收的目的
	
	缺点:空间占用高、利用率低
	
3. 标记整理

	1)标记:对所有GCRoots可达对象进行标记
		
	2)整理:然后将标记对象移向内存一端,清除另一端的对象(也就是需要回收的对象)
	
	优点:因为所有存活对象移向一端,不会出现大量不连续的内存空间(内存碎片化度低)
	
	主要适合老年代的对象存储
	
4. 分代收集

	根据新生代(Young Generation)和老年代(Old Generation)的特点采取最适当的收集算法
	
	1)新生代:复制算法
	
		新生代GC比较频繁,存活对象较少,因此复制算法效率较高
		
	2)老年代:标记整理 / 标记清除
	
		老年代对象存活率高,回收对象少,因此,可以采用标记整理或者标记清除

垃圾回收(GC)

什么对象需要回收

对于JVM来说,不会被使用的对象就应该被回收,以便腾出内存空间,JVM有2种方式判断对象是否需要回收

1. 引用计数法

	对对象的引用进行计数,引用计数为0的一定是可以回收的对象
	
	但是也存在引用计数不为0,但是可以回收的对象,例如2个无用对象相互引用,这就有了可达性分析
		
2. 可达性分析

	对于每一个活动对象,都存在以GC Roots为起点的引用路径,也叫对象可达路径
	
	当一个对象与GC Roots间没有可达路径时,则代表该对象可被回收

什么时候进行GC

1. 新生代:MinorGC

	当新生代的Eden区满了,无法存入新生对象,进行新生代的GC,这样的GC称为MinorGC
	
2. 老年代:MajorGC

	新生代GC,有的对象可能晋升到老年代,造成老年代使用内存上升,如果此时老年代内存不足,则触发GC
	
	* 对于CMS,可以单独对老年代进行GC,其它的收集器会进行Full GC,所以通常Major GC 等同于Full GC

3. Full GC

	Full Gc 会回收新生代、老年代还有永久代(需要看版本,1.8没有永久代)的不可达对象,也就是说:
	
	Full GC 会触发 Minor GC 和 Major GC
	
	触发Full GC的时机:
	
	1)新生代平均晋升对象大小占用空间大于老年代剩余空间,触发Full GC,而不是只触发Young GC
		
	2)如果存在永久代(Permanent Generation),当永久代没有足够内存,触发Young GC
		
	3)显示调用System.gc()通知GC有可能会触发GC,此时的GC也是Full GC

如何进行GC

1. 新生代

	新生代发生的是MinorGC,采用的是复制算法,当进行MinorGC时,过程如下:
	
	1)将Eden和survivor0区(survivor from)的存活对象复制到survivor1区(survivor to)
	
		注意:如果无法复制到survivor1区,则对象晋升到老年代
	
	2)清除Eden与survivor0区(survivor from)的内存
	
	3)将survivor1区的存活对象与survivor0区的幸存对象进行交换

2. 老年代

	老年代发生的是MajorGC,采用的是标记清除 / 标记整理

垃圾收集器

1. JVM有3种类型的垃圾收集器:串行收集器,并行收集器,并发收集器

	串行(Serial):只有一个线程去执行GC,并且会暂停其它工作线程直到GC完成
	
	并行(Parallel):多个线程去执行GC,也会暂停所有工作线程直到GC完成
	
	并发(concurrent):GC线程和工作线程同时执行
	
2. 串行收集器
	
	SerialGC	-- 新生代串行垃圾收集器
		
		使用单线程、复制算法
	
	Serial Old	-- 老年代串行垃圾收集器
	
		使用单线程、标记整理
		
3. 并行收集器

	ParNew	-- 新生代并行垃圾收集器
		
		使用多线程、复制算法
		
	Parallel Scavenge 收集器 -- 新生代并行垃圾收集器
	
		使用多线程、复制算法
	
	ParallelOld 	-- 老年代并行垃圾收集器
	
		使用多线程、标记整理
		
4. Parallel Scavenge

	Parallel Scavenge相比于ParNew的最大区别就是:吞吐量优先,能够设置垃圾收集停顿时间
	
	Parallel Scavenge是以吞吐量优先的收集器,旨在实现可控的吞吐量

		可以将这里的吞吐量理解成:运行用户代码时间 /(运行用户代码时间 + 垃圾收集时间)
			
    Parallel Scavenge控制吞吐量的参数:
        -XX:MaxGCPauseMillis	控制最大垃圾收集停顿时间,大于0的ms值,这是牺牲
        -XX:GCTimeRatio			直接设置吞吐量的比值,(0,100)的整数

		MaxGCPauseMillis是牺牲吞吐量和新生代空间来换取的,并不是设置越低越好
		假设GCTimeRatio值为n,那么系统将花费不超过 1/(1+n) 的时间用于垃圾收集

	Parallel Scavenge提供GC自适应的调节策略(GC Ergonomics):-XX:+UseAdaptiveSizePolicy

		当采用该策略,新生代的大小(-Xmn)、Eden与Survivor区的比例(-XX:SurvivorRatio)
		晋升老年代对象年龄(-XX:PretenureSizeThreshold)等参数不需要手动设置
		
		JVM根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间或者最大的吞吐量

5. 并发收集器CMS:ConcMarkSweepGC(老年代并发垃圾收集器)

	CMS是以最短垃圾回收停顿时间为目标的垃圾收集器,采用并发标记清除
		
	对响应时间的需求大于吞吐量的需求可以使用CMS并发收集
	
	CMS回收过程:
	
	1)初始标记(CMS initial mark):标记 GC Roots 能直接关联到的对象
	
	2)并发标记(CMS concurrent mark):可以和用户线程并行执行,标记所有可达对象
	
	3)重新标记(CMS remark):标记并发标记过程中用户线程产生的垃圾对象
	
	4)并发清除(CMS concurrent sweep):和用户线程可以并行执行,清除标记过的对象

	优点:并发、低停顿
		
	缺点:产生大量内存碎片,空间利用率不高
		
6. G1垃圾收集器:可对新生代和老年代进行回收(java9默认垃圾回收器)
		
	G1:大体流程来看是基于标记整理
	
	G1:基于并发,采用复制算法
	
    将堆在逻辑上划分为多个Region

    1) 初始标记:标记GC Roots的直接引用对象

    2) 并发标记:进行可达性分析,标记所有GCRoots的对象引用

    3) 最终标记:对并发标记期间的对象进行重新标记

    4) 筛选回收:对Region进行垃圾回收

垃圾收集器相关参数

串行收集器
参数描述
-XX:+UseSerialGC在新生代和老年代使用串行回收器
-XX:+SuivivorRatio设置 eden 区大小和 survivor 区大小的比例
-XX:+PretenureSizeThreshold设置大对象直接进入老年代的阈值,当对象的大小超过这个值时,将直接在老年代分配
-XX:MaxTenuringThreshold设置对象进入老年代的年龄的最大值,每一次 Minor GC 后,对象年龄就加 1,任何大于这个年龄的对象,一定会进入老年代
并行收集器
参数描述
-XX:+UseParNewGC在新生代使用并行收集器
-XX:+UseParallelOldGC老年代使用并行回收收集器
-XX:ParallelGCThreads设置用于垃圾回收的线程数,通常情况下可以和 CPU 数量相等。但在 CPU 数量比较多的情况下,设置相对较小的数值也是合理的
-XX:MaxGCPauseMills设置最大垃圾收集停顿时间。它的值是一个大于 0 的整数。收集器在工作时,会调整 Java 堆大小或者其他一些参数,尽可能地把停顿时间控制在 MaxGCPauseMills 以内
-XX:GCTimeRatio设置吞吐量大小,它的值是一个 0-100 之间的整数。假设 GCTimeRatio 的值为 n,那么系统将花费不超过 1/(1+n) 的时间用于垃圾收集
-XX:+UseAdaptiveSizePolicy打开自适应 GC 策略。在这种模式下,新生代的大小,eden 和 survivor 的比例、晋升老年代的对象年龄等参数会被自动调整,以达到在堆大小、吞吐量和停顿时间之间的平衡点
CMS
参数描述
-XX:+UseConcMarkSweepGC新生代使用并行收集器,老年代使用 CMS+串行收集器
-XX:+ParallelCMSThreads设定 CMS 的线程数量
-XX:+CMSInitiatingOccupancyFraction设置 CMS 收集器在老年代空间被使用多少后触发,默认为 68%
-XX:+UseFullGCsBeforeCompaction设定进行多少次 CMS 垃圾回收后,进行一次内存压缩
-XX:+CMSClassUnloadingEnabled允许对类元数据进行回收
-XX:+CMSParallelRemarkEndable启用并行重标记
-XX:CMSInitatingPermOccupancyFraction当永久区占用率达到这一百分比后,启动 CMS 回收,前提是-XX:+CMSClassUnloadingEnabled 激活了
-XX:UseCMSInitatingOccupancyOnly表示只在到达阈值的时候,才进行 CMS 回收
-XX:+CMSIncrementalMode使用增量模式,比较适合单 CPU
G1
参数描述
-XX:+UseG1GC使用 G1 回收器
-XX:+UnlockExperimentalVMOptions允许使用实验性参数
-XX:+MaxGCPauseMills设置最大垃圾收集停顿时间
-XX:+GCPauseIntervalMills设置停顿间隔时间
其它
参数描述
-XX:+DisableExplicitGC禁用显示 GC

JVM设置参数

参数描述
-Xms初始堆大小,-Xms1024m
-Xmx最大堆大小,-Xmx2048m
-Xmn新生代大小,通常为Xms的1/3或1/4,包括Eden和2个survivor区
-Xss每个线程堆栈的大小,默认为1M,JDK1.5+支持
-XX:NewRatio新生代:老年代,-XXNewRatio=2,代表新生代占1/3,老年代占2/3
-XX:SurvivorRatioEden:survivor,默认为8,即Eden占8/10,survivor0和1各占1/10
-XX:PermSize永久代的大小
-XX:MaxPermSize永久代的最大值
-XX:+PrintGCDetails打印GC信息
-XX:+HeapDumpOnOutOfMemoryError让JVM发生内存溢出时Dump出内存堆转储快照,方便分析原因

GC调试参数解释

S0C:新生代survivor0的大小
S1C:新生代survivor1大小
S0U:新生代survivor0的使用大小
S1U:新生代survivor1的使用大小
EC:Eden的大小
EU:Eden的使用大小
OC:老年代大小
OU:老年代使用大小
MC:方法区大小
MU:方法区使用大小
CCSC:压缩类空间大小
CCSU:压缩类空间使用大小

YGC:年轻代垃圾回收次数
YGCT:年轻代垃圾回收消耗时间
FGC:老年代垃圾回收次数
FGCT:老年代垃圾回收消耗时间
GCT:垃圾回收消耗总时间
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值