Java 虚拟机之垃圾回收

2019-03-22  本文已影响0人  末日声箫

Java 虚拟机之垃圾回收

主要针对的区域是java堆和方法区,相对于程序计数器,虚拟机栈和本地方法栈这三个随线程而生随线程而灭,其所需内存大小基本上在类结构确定的时候便已经确定的区域来说,这两个区域需要的内存只有在程序运行时才知道,所以这部分的内存分配和回收都是动态的,gc的主要区域也是这部分。其中gc最频繁的区域时java堆。

一 对象存活判定算法

1.1 引用计数法

给对象添加一个应用计数器,每当有一个地方引用时,就加1,当引用失效时,引用计数器就减1。当引用计数器为0时便表示这个对象不可能再被引用了,就可以进行回收了。

弊端:当两个对象互相循环引用时,此时除了他们之间的这种互相引用关系之外再无其他引用,这种情况这两个对象实际上是已经不存在的,但是却无法回收。 比如A.i=B,B.i=A;只有A在访问B,B在访问A,除此再没有其他地方再引用他们,他们是两个孤立的群体,是应该被回收的对象。但是他们的引用计数器没有为0,导致不能被回收。

1.2 可达性分析

基本思路是:以gc roots为起点,从这个起点往下搜索,搜索所走过的路径称为引用链,当一个对象到gc roots没有任何引用链的时候,这个对象到gc roots便不可达,也就是对象是不可用的。

可达性分析.png

可作为gc roots的对象:

二 垃圾搜集算法

2.1 标记清除

分为两个阶段:

不足:

2.2 复制算法

将内存分为相等的两块,每次只使用其中一块,当一块用完了之后就将这一块存活的对象复制到另一块,然后把这一块清理掉。

不足:

java 中的新生代98%都是“朝生夕死”,所以不需要按照1:1来分配。是eden 2Survivor 按照8:1 这样只有10%被浪费。

2.3 标记整理

分为两步:

不足:不快

2.4 分代收集

对于存活率低的采用复制算法,对于存活率高的采用另外两种。java虚拟机采用的是:新生代采用复制算法,老年代采用标记清除或者标记整理算法。

三 垃圾收集器

3.1 Serial,Serial Old收集器

Serial 针对新生代,采用的是复制算法,Serial old针对老年代,采用标记整理算法

3.2 ParNew,ParNew Old收集器

ParNew 针对新生代,采用的是复制算法,ParNew old针对老年代,采用标记整理算法

Serial 的多线程版本

3.3 Parallel Scavenge 收集器

针对新生代,采用的是复制算法

cms等收集器的关注点是尽可能控制gc时用户线程的停顿时间,而 这个收集器的目标是达到一个可控制的吞吐量。吞吐量=运行用户代码时间/(运行用户代码时间+gc时间)。

3.4 CMS

目标:获得最短停顿时间

算法:标记清除

步骤:

可见只有在两个耗时很短的过程才 stop the word,极大的减少了停顿时间

不足:

G1收集器

他会把内存分成一个个小区域,在这个小区域之间采用复制算法,然后又把这些小区域看着是一个单独的个体,他们之间采用标记整理算法。这样在小区域间采用复制算法,空间浪费就不那么严重。然后在他们之间又采用标记整理,时间上也不像对每一个单独的小个体进行标记整理那么耗时。

四 内存分配和回收策略

先来看看java堆的布局,java堆分为老年代和新生代两个区域,其中新生代又按照8:1的比例分为:eden 和 Survivor

java 堆布局.png

对象的分配策略:

上一篇 下一篇

猜你喜欢

热点阅读