【十七】JVM内存分配、垃圾回收算法、垃圾回收器

本篇是对《深入理解Java虚拟机----JVM高级特性与最佳实践》周志明作的第二版对应内容的一个读书笔记。

先贴上JVM运行时数据区的图

【十七】JVM内存分配、垃圾回收算法、垃圾回收器_第1张图片

其中:程序计数器、虚拟机栈、本地方法栈这3个区域,都是随线程而生,随线程而死。不需要过多的考虑垃圾回收的问题

垃圾回收需要考虑的是:1.方法区 2.堆

一、内存分配与回收

1.1 方法区

属于永久代 perm generation

主要回收2个部分

1.1.1 废弃常量

没有引用的常量

1.1.2 无用类

无用类必须同时满足3个条件

1.该类所有的实例都已经被回收

2.加载该类的ClassLoader已经被回收

3.该类对应的java.lang.Class对象没有在任务地方被引用,无法在任何地方通过反射访问该类的方法

1.2 堆

堆空间分为新生代老年代

1.2.1 新生代 Young generation

新生代中又分为:1个Eden区和2个Surivor区

Young generation = Eden(80%)+Survivor(10%)+Survivor(10%)

内存占比是8:1:1

比如设置参数 -Xms20M -Xmx20M -Xmn10M -XX:SurvivorRatio=8

表示堆空间最大20M,最小20M,其中新生代10M(那么老年代就是20-10=10M),新生代中Eden区与一个Survivor区比例为8:1

新生代可总共可用空间=Eden区+1个Survivor区另一个Survivor区保留区域。

新生代在垃圾回收算法:复制算法

垃圾回收的时候把Eden区和一个可用的Survivor区中存活的对象复制到另一个保留的Survivor区中,然后清理到Eden区和一个可用的Survivor区所有内容。

新生代内存分配:

1.对象优先在Eden分配。当Eden区没有足够空间进行分配时,虚拟机将发起一次Minor GC

新生代的垃圾回收Minor GC:

 1.Minor GC就是新生代的垃圾回收,它会把Eden和使用的那一个Survivor区的存活的对象都复制到保留的Survivor区中,然后清除到Eden和使用的那一个Survivor区。

如果保留的Survivor区装不下,则通过分配担保机制将其提前转移到老年代

1.2.2 老年代  Tenured generation

老年代内存分配:

1.大对象直接进入老年代。比如很长的字符串以及数组。

在使用Serial或者ParNew垃圾回收器的情况下,可以设置参数-XX:PretenureSizeThreshold的值指定大于该值的对象直接在老年代分配。

2.长期存活的对象将进入老年代

长期存活判断标准1:如果对象在Eden出生并经过第一次Minor GC后仍然存活,并且能被Survivor容纳的话,将被移动到Survivor空间中,并且对象年龄设为1。对象在Survivor区中每熬过一次Minor GC,年龄就增加1岁,当它的年龄增加到一定程度(默认是15岁),将会被晋升到老年代中。

对象晋升老年代的年龄阈值可以通过参数-XX:MaxTenuringThreshold设置。

长期存活判断标准2:如果在Survivor空间中相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于等于该年龄的对象就可以直接进入老年代,无需等到MaxTenuringThreshold中要求的年龄。

老年代的垃圾回收

1.Major GC

2.Full GC

老年代的垃圾回收算法:

标记----清理或者标记----整理,由使用的垃圾回收器决定。 

二、垃圾回收算法

2.1标记----清理算法 Mark-Sweep

首先标记出所有需要回收的对象,在标记完成后同一回收所有被标记的对象。这是最基础的收集算法。

缺点:效率低。标记清楚后会产生大量不连续的内存碎片

【十七】JVM内存分配、垃圾回收算法、垃圾回收器_第2张图片

2.2 复制算法 Copying

它将可用内存划分为大小相等的两块,每次使用其中一块,当这一块内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已经使用过的内存空间一次清理掉

【十七】JVM内存分配、垃圾回收算法、垃圾回收器_第3张图片

2.3 标记----整理算法  Mark-Compact

标记过程仍然与标记----清除算法一样,后续是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。

【十七】JVM内存分配、垃圾回收算法、垃圾回收器_第4张图片

三、垃圾回收器

垃圾回收器就是对垃圾回收算法的实现。

【十七】JVM内存分配、垃圾回收算法、垃圾回收器_第5张图片

有空再细讲

这里先列个表格总结一下就是了

名字 新生代/老年代 单/多线程 垃圾回收算法 Client/Server Stop the world 特点
Serial 新生代 复制算法

Client下

默认使用

YES  
ParNew 新生代 复制算法

Server下

首选

YES  
Parallel Scavenge 新生代 复制算法   YES

吞吐量优先

可设置吞吐量大小、最大垃圾收集停顿时间

吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间)

Serial Old

(MSC)

老年代 标记----整理算法 Client

默认使用

YES  
parallel Old 老年代 标记----整理算法     可以与Parallel Scavenge组合使用
CMS 老年代 / 标记----清除算法

Server

推荐

1.初始标记阶段:YES,单线程

2.并发标记阶段:NO,单线程

3.重新标记阶段:YES,多线程

4.并发清除阶段:NO,单线程

尽可能缩短垃圾收集时,用户线程的停顿时间
G1 新生代/老年代 /

整体:标记----整理算法

局部(两个Region之间):复制算法

Server

1.初始标记阶段:YES,单线程

2.并发标记阶段:NO,单线程

3.最终标记阶段:YES,多线程

4.筛选回收阶段:YES,多线程

1.可预测的停顿。能让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒

2.将Java堆划分为多个大小相等的独立区域Region

3.保留分代收集的概念,但是新生代和老年代不再物理隔离,他们都是一部分Region(不需要连续)的集合

 

你可能感兴趣的:(Java)