Java垃圾收集器与内存分配策略

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/kukubao207/article/details/86681858

1 概述

哪些内存需要回收?

什么时候回收?

如何回收?

Java垃圾回收主要关注的是堆和方法区。

2 Java如何判断对象存活?

有种算法是引用计数算法,给每一个对象添加一个引用计数器,每当有一个地方引用他,计数器值+1,引用失效时,计数器值-1。

任何时刻计数器为0的对象就是不可能在被使用的。但这种算法无法解决循环引用的问题。

因此Java是通过可达性分析算法来判定对象是否存活的。

GC Roots到该对象是否存在引用链就是判断对象是否存活的依据。

GC Roots对象的几种类型:

扫描二维码关注公众号,回复: 5787134 查看本文章

虚拟机栈中引用的对象。

方法区中类静态属性引用的对象。

方法区中常量引用的对象。

本地方法栈中JNI引用的对象。

3 引用

强引用:在程序代码中普遍存在的。这类引用不会被垃圾回收。

软引用:在内存溢出异常之前,不会被GC回收。

弱引用:生存到下一次GC发生之间。

虚引用:唯一目的在于对象被收集器回收之前收到一个系统通知

4 对象面对垃圾回收的自救

在finalize()中重新与引用链上的任何一个对象建立关联。

但finalize只会执行一次。

5 回收方法区

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

该类的实例都已被回收,Java堆中不存在该类的实例。

加载该类的ClassLoader已被回收。

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

6 垃圾回收算法

标记-清除算法--标记已经死亡的对象,然后清除这些对象的内存。

复制算法--把活着的对象复制到另一块内存区域,然后把当前这一块内存区域对象全部清除,回收内存。

标记-整理算法--标记已经死亡的对象,让存活的对象向一端移动,然后直接清理掉端边界以外的内存。

 

7 垃圾收集器

新生代收集器

Serial收集器

特点:单线程收集器,使用一个CPU或者一条收集线程去GC,在GC时暂停其他所有工作线程(Stop The World)。

使用场景:Clien模式下的虚拟机

ParNew收集器

特点:Serial收集器的多线程版本,同样需要Stop The World。

使用场景:Server模式下的虚拟机(目前只有它能与CMS收集器配合工作)、多CPU

Parallel Scavenge收集器

特点:他不关注缩短用户线程的停顿时间,而是关注系统有一个更高的吞吐量(用户代码时间/(GC时间+用户代码时间)),也叫“吞吐量优先”收集器

使用场景:后台运算量高的,对CPU能有较好的利用率。不适合于用户交互的程序。

 

老年代收集器

Serial Old收集器

特点:Serial收集器的老年代版本,使用“标记--整理”算法

使用场景:Client模式下的虚拟机使用

Parallel Old收集器

特点:Parallel Scavenge收集器的老年代版本,使用多线程和“标记--整理”算法。

使用场景:注重吞吐量以及CPU资源敏感的场合,用Parallel Scavenge + Parallel Old。

CMS收集器

特点:

1.并发收集:并发标记和并发清除过程收集器线程都可以与用户线程一起工作

2.低停顿:服务器响应速度较快,系统停顿时间短,用户体验好。

3.使用标记--清除算法:   初始标记 -> 并发标记 -> 重新标记 -> 并发清除

缺点:

1.对CPU资源敏感,占用一部分CPU资源导致应用程序变慢,总吞吐量降低。

2.无法处理浮动垃圾,由于并发清除阶段,用户线程还有垃圾产生,这部分标记后,无法在当次清除,只能下次GC清除。

3.空间碎片较多,不利于大对象分配,容易导致Full GC,这是标记--清除算法的缺点。

使用场景:

重视服务器响应速度、希望系统停顿时间短的需求。

 

G1收集器

特点:并发与并行、分代收集(不需要其他收集器配合)、空间整合(标记--整理)、可预测的停顿。

未完待续

猜你喜欢

转载自blog.csdn.net/kukubao207/article/details/86681858