JVM虚拟机(四):JVM 垃圾回收机制概念及其算法
垃圾回收概念和其算法
谈到垃圾回收(Garbage Collection)GC,需要先澄清什么是垃圾,类比日常生活中的垃圾,我们会把他们丢入垃圾箱,然后倒掉。GC中的垃圾,特指存于内存中、不会再被使用的对象,儿回收就是相当于把垃圾“倒掉”。垃圾回收有很多中算法:如 引用计数法、标记压缩法、复制算法、分代、分区的思想。
垃圾收集算法
引用计数法:就是个比较古老而经典的垃圾收集算法,其核心就是在对象被其他所引用计数器加1,而当引用时效时则减1,但是这种方式有非常严重的问题:无法处理循环引用的情况、还有就是每次进行加减操作比较浪费系统性能。
标记清除法:分为标记和清除两个阶段进行处理内存中的对象,当然这种方式也有非常大的弊端,就是空间碎片问题,垃圾回收后的空间不是连续的,不连续的内存空间的工作效率要低于连续的内存空间。
复制算法:其核心思想就是将内存空间分为两块,每次只使用其中一块,在垃圾回收时,将正在使用的内存中的存留对象复制到未被使用的内存块中去,之后去清除之前正在使用的内存快中的所有的对象,反复去交换两个内存的角色,完成垃圾收集。
(java中的新生代的from和to空间使用的就是这个算法)
标记压缩法:标记压缩法在标记清除基础之上做了优化,把存活的对象压缩到内存一端,而后进行垃圾清理。(java中老年代使用的就是标记压缩法)
图解新生代使用的复制算法:
文字说明:
新生代中没有GC过的对象在eden区,然后进行GC一次,进入到s0区。然后再次进行GC得时候,就回去S0区去查看这个对象有没有在使用,如果在使用那就把这个对象复制到s1区,然后清除s0区不再使用的对象。再次GC的时候就去S1区,再看看这个对象有没有在使用,如果还在使用,那就复制到S0区。然后清除S1区不在使用的对象。
图解老年代算法:
文字说明:
进行GC时看看老年代有没有在使用的对象,如果有那么就压缩出一个区域把那些实用的对象放到压缩的区域中,然后把不再使用的对象全部回收掉。
为什么老年代使用标记压缩法:因为是老年代的对象相对比较稳定了,使用的次数较多。假设老年代中的对象有一百个,这时老年代进行一次垃圾回收可能就会收集几个对象。
文字说明:
进行GC时看看老年代有没有在使用的对象,如果有那么就压缩出一个区域把那些实用的对象放到压缩的区域中,然后把不再使用的对象全部回收掉。
分代算法:就是根据对象的特点把内存分成N块,而后根据每个内存的特点使用不同的算法。
对于新生代和老年代来说,新生代回收频率很高,但是每次回收耗时都很短,而老年待回收频率较低,但是耗时会相对较长,所以应该尽量减少老年代的GC
垃圾回收时的停顿现象
垃圾回收器的任务是识别和回收垃圾对象进行内存处理,为了让垃圾回收器可以高效地执行,一大部分情况下,会要求系统进入一个停顿的状态。停顿的目的是终止所有应用线程,只有这样系统才不会有新的垃圾产生,童年故事停顿保证了系统状态在某一个瞬间的一致性,也有益于更好的低标记垃圾对象。因此在垃圾回收时,都会产生应用程序的停顿。
对象如何进入老年代
一般而言对象首次创建被放置在新生代的eden区,如果没有GC介入,则对象不会离开eden区,那么eden区的对象如何进入老年代呢?一般来讲,只要对象的年龄达到一定得大小,就会自动离开年轻代进入老年代,对象年龄是由对象经理次数GC决定的,在新生代每次GC之后如果没有被回收则年纪加1,虚拟机提供了一个参数来控制新生代对象的最大年龄,当超过这个年龄范围就会晋升老年代。
-XX:MaxTenuringThreshold,默认情况下为15.
package com.base001; import java.util.HashMap;
import java.util.Map; public class Test05 { public static void main(String[] args) {
//初始的对象在eden区
//参数:-Xmx64M -Xms64M -XX:+PrintGCDetails
for(int i=0; i< 5; i++){
byte[] b = new byte[1024*1024];
} //测试进入老年代的对象
//
//参数:-Xmx1024M -Xms1024M -XX:+UseSerialGC -XX:MaxTenuringThreshold=15 -XX:+PrintGCDetails
//-XX:+PrintHeapAtGC
// Map<Integer, byte[]> m = new HashMap<Integer, byte[]>();
// for(int i =0; i <5 ; i++) {
// byte[] b = new byte[1024*1024];
// m.put(i, b);
// }
//
// for(int k = 0; k<20; k++) {
// for(int j = 0; j<300; j++){
// byte[] b = new byte[1024*1024];
// }
// } }
}
总结:根据设置的MaxTenuringThreshold参数,可以指定新生代对象经过多少次回收后进入老年代。
另外大对象(新生代eden区无法装入时,也会直接进入老年代)。JVM里有个参数可以设置对象的大小超过在指定的大小之后,直接晋级老年代。
-XX:PretenureSizeThreshold
package com.base001; import java.util.HashMap;
import java.util.Map; public class Test05 { public static void main(String[] args) {
//初始的对象在eden区
//参数:-Xmx64M -Xms64M -XX:+PrintGCDetails
/*for(int i=0; i< 5; i++){
byte[] b = new byte[1024*1024];
}*/ //测试进入老年代的对象
//
//参数:-Xmx1024M -Xms1024M -XX:+UseSerialGC -XX:MaxTenuringThreshold=15 -XX:+PrintGCDetails
//-XX:+PrintHeapAtGC
Map<Integer, byte[]> m = new HashMap<Integer, byte[]>();
for(int i =0; i <5 ; i++) {
byte[] b = new byte[1024*1024];
m.put(i, b);
} for(int k = 0; k<20; k++) {
for(int j = 0; j<300; j++){
byte[] b = new byte[1024*1024];
}
} }
}
运行后的控制台:
[GC[DefNew: 279476K->5567K(314560K), 0.0093556 secs] 279476K->5567K(1013632K), 0.0242877 secs] [Times: user=0.00 sys=0.00, real=0.03 secs]
[GC[DefNew: 285156K->5567K(314560K), 0.0033584 secs] 285156K->5567K(1013632K), 0.0033896 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC[DefNew: 284949K->5567K(314560K), 0.0020226 secs] 284949K->5567K(1013632K), 0.0020704 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC[DefNew: 284306K->5567K(314560K), 0.0022780 secs] 284306K->5567K(1013632K), 0.0023128 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC[DefNew: 284908K->5567K(314560K), 0.0027272 secs] 284908K->5567K(1013632K), 0.0027671 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC[DefNew: 284630K->5567K(314560K), 0.0022646 secs] 284630K->5567K(1013632K), 0.0023033 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC[DefNew: 284448K->5567K(314560K), 0.0020810 secs] 284448K->5567K(1013632K), 0.0021280 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC[DefNew: 284328K->5567K(314560K), 0.0028784 secs] 284328K->5567K(1013632K), 0.0029179 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC[DefNew: 284250K->5567K(314560K), 0.0027738 secs] 284250K->5567K(1013632K), 0.0028109 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC[DefNew: 284198K->5567K(314560K), 0.0027430 secs] 284198K->5567K(1013632K), 0.0027896 secs] [Times: user=0.02 sys=0.00, real=0.00 secs]
[GC[DefNew: 284164K->5567K(314560K), 0.0027639 secs] 284164K->5567K(1013632K), 0.0028058 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC[DefNew: 285166K->5567K(314560K), 0.0027197 secs] 285166K->5567K(1013632K), 0.0027675 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC[DefNew: 285151K->5567K(314560K), 0.0031070 secs] 285151K->5567K(1013632K), 0.0031417 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC[DefNew: 285141K->5567K(314560K), 0.0021324 secs] 285141K->5567K(1013632K), 0.0021730 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC[DefNew: 285135K->5567K(314560K), 0.0023313 secs] 285135K->5567K(1013632K), 0.0023660 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC[DefNew: 285131K->0K(314560K), 0.0041250 secs] 285131K->5567K(1013632K), 0.0041664 secs] [Times: user=0.02 sys=0.00, real=0.00 secs]
[GC[DefNew: 279561K->0K(314560K), 0.0008313 secs] 285128K->5567K(1013632K), 0.0008688 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC[DefNew: 279563K->0K(314560K), 0.0001259 secs] 285130K->5567K(1013632K), 0.0001630 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC[DefNew: 279560K->0K(314560K), 0.0001164 secs] 285127K->5567K(1013632K), 0.0001543 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC[DefNew: 279562K->0K(314560K), 0.0001204 secs] 285129K->5567K(1013632K), 0.0001686 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC[DefNew: 279562K->0K(314560K), 0.0001089 secs] 285129K->5567K(1013632K), 0.0001926 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC[DefNew: 279562K->0K(314560K), 0.0001157 secs] 285129K->5567K(1013632K), 0.0001500 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
Heap
def new generation total 314560K, used 30170K [0x0f200000, 0x24750000, 0x24750000)
eden space 279616K, 10% used [0x0f200000, 0x10f76b30, 0x20310000)
from space 34944K, 0% used [0x20310000, 0x20310000, 0x22530000)
to space 34944K, 0% used [0x22530000, 0x22530000, 0x24750000)
tenured generation total 699072K, used 5567K [0x24750000, 0x4f200000, 0x4f200000)
the space 699072K, 0% used [0x24750000, 0x24cbfc18, 0x24cbfe00, 0x4f200000)
compacting perm gen total 12288K, used 1656K [0x4f200000, 0x4fe00000, 0x53200000)
the space 12288K, 13% used [0x4f200000, 0x4f39e140, 0x4f39e200, 0x4fe00000)
No shared spaces configured.
总结:使用ProtenureSizeThreshold可以进行指定进入老年代的对象大小,但是要注意TLAB区域优先分配空间
TLAB
TLAB(Thread Local Allocation Buffer)即线程本地分配缓存,从名字上看是一个线程专用的内存分配区域,是为了加速对象分配而生的。每一个线程都会产生一个TLAB,该县城独享的工作区域,java虚拟机使用这种TLAB区来避免多线程冲突问题,提高了对象分配的效率。TLAB空间一般不会太大,当大对象无法在TLAB分配时,则会直接分配到堆上。
-XX:UserTLAB 使用TLAB
-XX:+TLABSize 设置TLAB大小
-XX:TLABRefillWasteFraction 设置维护进入TLAB空间的单个对象大小,它是一个比例值,默认为64,即如果对象大于整个空间的1/64,则在堆创建对象。
-XX:+PrintTLAB 查看TLAB信息
-XX:ResizeTLAB自调整TLABRefillWasteFraction阈值。
package com.base001; public class Test07 { public static void alloc(){
byte[] b = new byte[2];
}
public static void main(String[] args) { //TLAB分配
//参数:-XX:+UseTLAB -XX:+PrintTLAB -XX:+PrintGC -XX:TLABSize=102400 -XX:-ResizeTLAB -XX:TLABRefillWasteFraction=100 -XX:-DoEscapeAnalysis -server
for(int i=0; i<10000000;i++){
alloc();
} }
}
运行控制台:
TLAB: gc thread: 0x001bbc00 [id: 7808] desired_size: 100KB slow allocs: 4 refill waste: 1024B alloc: 0.29593 5000KB refills: 168 waste 0.0% gc: 0B slow: 2864B fast: 0B
TLAB totals: thrds: 1 refills: 168 max: 168 slow allocs: 4 max 4 waste: 0.0% gc: 0B max: 0B slow: 2864B max: 2864B fast: 0B max: 0B
[GC 16896K->472K(62976K), 0.0012987 secs]
TLAB: gc thread: 0x08697400 [id: 9448] desired_size: 100KB slow allocs: 0 refill waste: 1024B alloc: 0.29593 5000KB refills: 1 waste 100.0% gc: 102368B slow: 0B fast: 0B
TLAB: gc thread: 0x08696400 [id: 8788] desired_size: 100KB slow allocs: 0 refill waste: 1024B alloc: 0.29593 5000KB refills: 1 waste 100.0% gc: 102400B slow: 0B fast: 0B
TLAB: gc thread: 0x001bbc00 [id: 7808] desired_size: 100KB slow allocs: 0 refill waste: 1024B alloc: 0.64512 10900KB refills: 167 waste 0.0% gc: 0B slow: 2672B fast: 0B
TLAB totals: thrds: 3 refills: 169 max: 167 slow allocs: 0 max 0 waste: 1.2% gc: 204768B max: 102400B slow: 2672B max: 2672B fast: 0B max: 0B
[GC 17368K->472K(62976K), 0.0008755 secs]
TLAB: gc thread: 0x001bbc00 [id: 7808] desired_size: 100KB slow allocs: 0 refill waste: 1024B alloc: 0.76527 12930KB refills: 169 waste 0.0% gc: 0B slow: 2704B fast: 0B
TLAB totals: thrds: 1 refills: 169 max: 169 slow allocs: 0 max 0 waste: 0.0% gc: 0B max: 0B slow: 2704B max: 2704B fast: 0B max: 0B
[GC 17368K->456K(62976K), 0.0007058 secs]
TLAB: gc thread: 0x001bbc00 [id: 7808] desired_size: 100KB slow allocs: 0 refill waste: 1024B alloc: 0.84751 14320KB refills: 169 waste 0.0% gc: 0B slow: 2704B fast: 0B
TLAB totals: thrds: 1 refills: 169 max: 169 slow allocs: 0 max 0 waste: 0.0% gc: 0B max: 0B slow: 2704B max: 2704B fast: 0B max: 0B
[GC 17352K->456K(79872K), 0.0008104 secs]
TLAB: gc thread: 0x001bbc00 [id: 7808] desired_size: 100KB slow allocs: 0 refill waste: 1024B alloc: 0.90096 30445KB refills: 338 waste 0.0% gc: 0B slow: 5408B fast: 0B
TLAB totals: thrds: 1 refills: 338 max: 338 slow allocs: 0 max 0 waste: 0.0% gc: 0B max: 0B slow: 5408B max: 5408B fast: 0B max: 0B
[GC 34248K->464K(79872K), 0.0009320 secs]
TLAB: gc thread: 0x001bbc00 [id: 7808] desired_size: 100KB slow allocs: 0 refill waste: 1024B alloc: 0.93571 31619KB refills: 338 waste 0.0% gc: 0B slow: 5408B fast: 0B
TLAB totals: thrds: 1 refills: 338 max: 338 slow allocs: 0 max 0 waste: 0.0% gc: 0B max: 0B slow: 5408B max: 5408B fast: 0B max: 0B
[GC 34256K->456K(111616K), 0.0008258 secs]
对象创建流程图
JVM虚拟机(四):JVM 垃圾回收机制概念及其算法的更多相关文章
- java面试题之----JVM架构和GC垃圾回收机制详解
JVM架构和GC垃圾回收机制详解 jvm,jre,jdk三者之间的关系 JRE (Java Run Environment):JRE包含了java底层的类库,该类库是由c/c++编写实现的 JDK ( ...
- JVM原理(Java代码编译和执行的整个过程+JVM内存管理及垃圾回收机制)
转载注明出处: http://blog.csdn.net/cutesource/article/details/5904501 JVM工作原理和特点主要是指操作系统装入JVM是通过jdk中Java.e ...
- JVM架构和GC垃圾回收机制
深入理解系列之JDK8下JVM虚拟机(1)——JVM内存组成 https://blog.csdn.net/u011552404/article/details/80306316 JVM架构和GC垃圾回 ...
- JVM内存分配与垃圾回收机制管理
项目上线,性能优化有个重要组成就是jvm内存分配和垃圾回收机制的管理配置. 网上随便能搜到相关的具体步骤,以及内存中各种参数对应的意义,不再赘述. 干货就是直接抛出遇到的问题,以及如何解决的,再说说待 ...
- JVM内存管理和垃圾回收机制介绍
http://backend.blog.163.com/blog/static/20229412620128233285220/ 内存管理和垃圾回收机制是JVM最核心的两个组成部分,对其内部实 ...
- JVM垃圾回收机制和常用算法
由于疫情的原因,所以目前一直在家远程办公,所以很多时间在刷面试题,发现2019大厂的面试虽然种类很多,但是总结了一下发现主要是这几点:算法和数据结构. JVM.集合.多线程.数据库这几点在面试的时候比 ...
- jvm垃圾回收机制和常见算法
这是朋友给的面试题里边的,具体地址已经找不到,只能对原作者说声抱歉了: 理论上来讲sun公司只定义了垃圾回收机制规则,而步局限于其实现算法,因此不同厂商生产的虚拟机采用的算法也不尽相同. GC(Gar ...
- JVM构架、GC垃圾回收机制的理解
JVM是Java Virtual Machine(Java虚拟机)的缩写 1.程序计数器 它的作用可以看做是当前线程所执行的字节码的行号指示器. 每个线程都有一个程序计算器,就是一个指针,指向方法区 ...
- 【Java_基础】JVM内存模型与垃圾回收机制
1. JVM内存模型 Java虚拟机在程序执行过程会把jvm的内存分为若干个不同的数据区域来管理,这些区域有自己的用途,以及创建和销毁时间. JVM内存模型如下图所示 1.1 程序计数器 程序计数器( ...
随机推荐
- Andorid之Annotation框架初使用(五)
注入res文件夹的资源: @StringRes @EActivity public class MyActivity extends Activity { @StringRes(R.string.he ...
- Android面试题-OkHttp3源码分析
本文配套视频: okhttp内核分析配套视频一 okhttp内核分析配套视频二 okhttp内核分析配套视频三 源码分析相关面试题 Volley源码分析 注解框架实现原理 基本使用 从使用方法出发,首 ...
- 将Maven2项目转为MyEclipse项目
现在项目中,大家开始用jetty.它不用像在MyEclipse中使用Tomcat那样要部署,也不用像在Tomcat中那样,要把应用都放到webapp文件夹下.jetty可以直接用你的项目的目录结构. ...
- iOS:二叉树多级表格的使用,使用三方库TreeTableView-master实现对json解析数据的递归遍历整理成树状结构
在项目中,我们有时需要使用二叉树来实现多级表格的递归遍历查询,如果对二叉树比较懂,那么写起来其实也不费事,为了节省开发时间,下面介绍一下第三方库TreeTableView-master,这个三方库上给 ...
- LoadLibrary文件路径及windows API相关的文件路径问题
LoadLibrary HMODULE WINAPI LoadLibrary( _In_ LPCTSTR lpFileName ); Loads the specified module into ...
- 利用FPGA实现PCI总线接口及Windows驱动实现
利用FPGA实现PCI总线接口及Windows驱动实现 关于PCI总线协议,资料网上.书本都是.这里我们仅仅对重点对利用FPGA实现PCI总线接口问题进行简单分析.下图是PCI总线接口信号: 配置空间 ...
- 如何在SharePoint的列表中使用通配符来filter出ListItem?
一个朋友问我这样一个问题, 他想要快速从SharePoint的文档库中filter出来名字中先带有一个Q, 接着一些其他的字符, 后面再跟着有一个数字20这样的文件. 第一个想法就是修改Share ...
- css整站规划
准备1 css reset /** * Eric Meyer's Reset CSS v2.0 (http://meyerweb.com/eric/tools/css/reset/) * http:/ ...
- PHP接收跨域请求header 头设置
header("Access-Control-Allow-Origin: http://a.com"); // 允许a.com发起的跨域请求 //如果需要设置允许所有域名发起的跨域 ...
- C# 使用int.TryParse,Convert.ToInt32,(int)将浮点类型转换整数时的区别
int.TryParse,Convert.ToInt32,(int) 这几种类型在将浮点类型转换整数时是有差别 Convert.ToInt32则会进行四舍五入 int.TryParse只能转换整数,即 ...