垃圾回收概念和其算法

谈到垃圾回收(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 垃圾回收机制概念及其算法的更多相关文章

  1. java面试题之----JVM架构和GC垃圾回收机制详解

    JVM架构和GC垃圾回收机制详解 jvm,jre,jdk三者之间的关系 JRE (Java Run Environment):JRE包含了java底层的类库,该类库是由c/c++编写实现的 JDK ( ...

  2. JVM原理(Java代码编译和执行的整个过程+JVM内存管理及垃圾回收机制)

    转载注明出处: http://blog.csdn.net/cutesource/article/details/5904501 JVM工作原理和特点主要是指操作系统装入JVM是通过jdk中Java.e ...

  3. JVM架构和GC垃圾回收机制

    深入理解系列之JDK8下JVM虚拟机(1)——JVM内存组成 https://blog.csdn.net/u011552404/article/details/80306316 JVM架构和GC垃圾回 ...

  4. JVM内存分配与垃圾回收机制管理

    项目上线,性能优化有个重要组成就是jvm内存分配和垃圾回收机制的管理配置. 网上随便能搜到相关的具体步骤,以及内存中各种参数对应的意义,不再赘述. 干货就是直接抛出遇到的问题,以及如何解决的,再说说待 ...

  5. JVM内存管理和垃圾回收机制介绍

    http://backend.blog.163.com/blog/static/20229412620128233285220/     内存管理和垃圾回收机制是JVM最核心的两个组成部分,对其内部实 ...

  6. JVM垃圾回收机制和常用算法

    由于疫情的原因,所以目前一直在家远程办公,所以很多时间在刷面试题,发现2019大厂的面试虽然种类很多,但是总结了一下发现主要是这几点:算法和数据结构. JVM.集合.多线程.数据库这几点在面试的时候比 ...

  7. jvm垃圾回收机制和常见算法

    这是朋友给的面试题里边的,具体地址已经找不到,只能对原作者说声抱歉了: 理论上来讲sun公司只定义了垃圾回收机制规则,而步局限于其实现算法,因此不同厂商生产的虚拟机采用的算法也不尽相同. GC(Gar ...

  8. JVM构架、GC垃圾回收机制的理解

     JVM是Java Virtual Machine(Java虚拟机)的缩写 1.程序计数器 它的作用可以看做是当前线程所执行的字节码的行号指示器. 每个线程都有一个程序计算器,就是一个指针,指向方法区 ...

  9. 【Java_基础】JVM内存模型与垃圾回收机制

    1. JVM内存模型 Java虚拟机在程序执行过程会把jvm的内存分为若干个不同的数据区域来管理,这些区域有自己的用途,以及创建和销毁时间. JVM内存模型如下图所示 1.1 程序计数器 程序计数器( ...

随机推荐

  1. redis+spring配置

    pom引入jedis的jar包 <dependency> <groupId>redis.clients</groupId> <artifactId>je ...

  2. 关于Unity3D的编辑器崩溃时的线索定位

    今天在Unity3D编辑器中进行功能測试的时候,编辑器突然崩溃了(就是整个窗体突然消失,进程直接结束)之后也没有不论什么错误报告信息提示.好吧,应该是偶现问题.我侥幸地想,我用的好歹也是正版啊,不应该 ...

  3. 由 12306.cn 谈谈高并发+高负载网站性能技术

    12306.cn 网站挂了,被全国人民骂了.我这两天也在思考这个事,我想以这个事来粗略地和大家讨论一下网站性能的问题.因为仓促,而且完全基于本人有限的经验和了解, 所以,如果有什么问题还请大家一起讨论 ...

  4. telnet用法 测试端口号

    Telnet是进行远程登录的标准协议和主要方式它为用户提供了在本地计算机上完成远程主机工作的能力.可以用telnet命令来测试端口号是否正常打开还是关闭状态. 工具/原料 电脑 cmd命令 方法/步骤 ...

  5. Drawable的getIntrinsicHeight()和getIntrinsicWidth()

    版权声明:本文为博主原创文章,未经博主允许不得转载. 今天遇到一个问题,一个Bitmap封装到BitmapDrawable中 ,BitmapDrawable drawable = new Bitmap ...

  6. iOS: 如何获取ios设备的当前IP地址

    有的时候,我们项目上线后,需要根据ip地址去统计不同地区的用户情况,此时IP地址的收取显得尤其重要,一般情况下,在用户登录时去获取用户的ip是准确的,当然实时追踪ip的变化而统计是更安全可靠的. ip ...

  7. SQL Server基础知识三十三问 (1-7)

    1. SQL Server运行在什么端口上? 可以被修改么? 答: 1433端口. 可以修改的, 在SQL Server Configuration Manager的SQL Server Networ ...

  8. [转载][概念]Storage Pool, Private RAID Group, Private LUN

    Storage Pool的起源 ========================== Some time ago, EMC introduced the concept of Virtual Prov ...

  9. SQL Server 2012不支持Microsoft Visual Studio Test Controller 2010

    折腾了一个上午, 发现Test Controller怎么都连不上SQL. 能尝试的都尝试了, 觉得应该看看是不是有不支持的问题.   找到了这篇. TFS 2010 will not support ...

  10. mac远程桌面Microsoft Remote Desktop for Mac的安装与使用

    mac远程桌面Microsoft Remote Desktop for Mac的安装与使用 学习了:https://blog.csdn.net/ytangdigl/article/details/78 ...