JAVA内存回收机制-GC

目录

一、基础概念:

二、判断对象是否为垃圾的算法

1.引用计数算法–判断对象的引用数量

2.可达性分析算法–判断对象的引用链是否可达

三、垃圾回收算法

1.标记清除算法(Mark and Sweep)

2.复制算法(Copying)

3.标记-整理算法(Mark-Compact)

4.分代收集算法(Generational Collector)

(1)年轻代 Minor GC

(2)老年代

四、常见的垃圾收集器

1.JVM运行模式

2.垃圾收集器之间的联系(总)

3.年轻代常见的收集器

(1)Serial收集器(复制算法)

(2)ParNew收集器(复制算法)

(3)ParallelScavenge(复制算法)

4.老年代的垃圾收集器

(1)Serial Old收集器(标记-整理算法)

(2)Parallel Old收集器(标记-整理算法)

(3)CMS(Concurrent Mark Sweep)收集器(标记-清除算法)

G1(Garbage First)收集器(复制+标记-整理)

五、面试题总结

1.Object的finalize方法作用是否与C++的析构函数作用相同?

2.强引用 软引用 弱引用 虚引用 引用队列

3.引用队列:

内存泄露与内存溢出

六、全文回顾


一、基础概念:

垃圾回收机制在Java堆中

对象被判定为垃圾的标准:没有被对象引用视为垃圾

二、判断对象是否为垃圾的算法

1.引用计数算法–判断对象的引用数量

优缺点

(1)优点:执行效率高,程序执行受影响较小
(2)缺点:无法检测循环引用的情况,导致内存泄露

如:父对象有一个对子对象的引用,子对象也有一个堆父对象的引用,那么计数器永远不可能为0;

主流的垃圾回收都不用它!

2.可达性分析算法–判断对象的引用链是否可达

通过判断对象的引用链是否可达来判定对象是否可以回收

可以作为GC Root的对象

  • 虚拟机栈中的引用对象(栈帧中的本地变量表)
  • 方法区中常量的引用对象
  • 方法区中类的静态属性引用对象
  • 本地方法Native的引用对象
  • 活跃线程的引用对象

 

三、垃圾回收算法

1.标记清除算法(Mark and Sweep)

可达对象被标记,没被标记的就清除

缺点:容易造成碎片化

由于标记清除不需要进行对象的移动,并且仅对不存活的对象进行处理,因此标记清除之后会产生大量不连续的碎片,空间碎片太多,可能会导致以后在程序运行过程中需要分配较大的对象时无法找到足够的连续内存,而不得不触发另一次垃圾收集工作

2.复制算法(Copying)

适合存活率低的算法

  • 分为对象面和空闲面
  • 对象在对象面上创建
  • 存活的对象从对象面复制到空闲面
  • 将对象面所有对象内存清除
    ①只是这种算法把内存缩小为原来的一半,代价高昂。
    ②复制算法在对象存活率比较高的时候,就要进行非常多的复制操作,使得效率变低。

3.标记-整理算法(Mark-Compact)

回收时候将存活对象整理到内存的一端

4.分代收集算法(Generational Collector)

是垃圾回收算法的组合拳
按照对象生命周期的不同来划分区域 采用不同的垃圾回收算法
JDK8 去除了永久代 只保留了年轻代和老年代 两者堆空间比例为1比2

GC的分类

  • Minor GC Eden区域满的时候触发
  • Full GC

 

(1)年轻代 Minor GC

尽可能快速回收生命周期短的对象

  • Eden区
  • 两个Survivor区
  • 两个区8:1:1

 

回收的具体过程:

1.Minor GC共有一个Eden区和两个Survivor区(假设为S0和S1)

2.首先将Eden区中存活的对象复制到其中一个Survivor(S0)中,并将对象的年龄标记为1,这个区成为from区

3.第二轮将Eden中和S0中存活的对象复制到S1中,并将对象的年龄+1,S0变为TO区,S1变为From区

4.依次类推,S0和S1交替成为FROM区和To区,直到年龄达到阈值(15代),则会被移动到老年代中

注:

 

(2)老年代


当触发老年代回收 通常会触发新生代的回收即整个堆的回收即Full GC
Full GC 比Minor GC慢

注:以上答出三点即可

四、常见的垃圾收集器

1.JVM运行模式

Client :启动速度较快

Server:启动速度较慢

-》但是启动进入稳定期长期运行时,Server较快

-》原因:Server采用重量级的虚拟机,对程序采用了更多的优化

-》查看java-version即可看到运行模式是哪个:

2.垃圾收集器之间的联系(总)

3.年轻代常见的收集器

(1)Serial收集器(复制算法)

  • 单线程收集,进程垃圾收集的时候 必须暂停所有工作线程
  • 简单高效,Client模式下默认的年轻代收集器

(2)ParNew收集器(复制算法)

  • 多线程收集,其他特点与Serial收集器一样
  • 单核执行不如Serial 多核下执行有优势

(3)ParallelScavenge(复制算法)

 

4.老年代的垃圾收集器

(1)Serial Old收集器(标记-整理算法)

  • 单线程收集,垃圾收集时暂停所有工作线程
  • 简单高效,Client模式下默认的老年代收集器

(2)Parallel Old收集器(标记-整理算法)

-》多线程 , 吞吐量优先

(3)CMS(Concurrent Mark Sweep)收集器(标记-清除算法)

  • 初始标记:stop the world
    从垃圾回收的根对象开始 只扫描到和根对象关联的对象 时间很快
  • 并发标记:主要标记过程,程序不会停顿
  • 并发预清理:查找执行并发标记从年轻代到老年代的对象 相当于两次 concurrent-mark. 因为上一次c mark,太长.会有很多 changed object 出现. stop the world 的 remark 阶段,changed object 会少很多.
    新生代晋升的对象、新分配到老年代的对象以及在并发阶段被修改了的对象。
  • 重新标记:暂停虚拟机,为了修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,重新新从GC Root开始查找新关联的对象,并进行标记;
    遍历新生代对象,重新标记
    根据GC Roots,重新标记
    遍历老年代的Dirty Card
  • 并发清理:清理垃圾对象,程序不会停顿
  • 并发重置:并发重设状态等待下次CMS的触发

注:会出现内存碎片

 

G1(Garbage First)收集器(复制+标记-整理)

(A)、初始标记(Initial Marking)
仅标记一下GC Roots能直接关联到的对象;
且修改TAMS(Next Top at Mark Start),让下一阶段并发运行时,用户程序能在正确可用的Region中创建新对象;
需要"Stop The World",但速度很快;

(B)、并发标记(Concurrent Marking)
进行GC Roots Tracing的过程;
刚才产生的集合中标记出存活对象;
耗时较长,但应用程序也在运行;
并不能保证可以标记出所有的存活对象;

(C)、最终标记(Final Marking)
为了修正并发标记期间因用户程序继续运作而导致标记变动的那一部分对象的标记记录;
上一阶段对象的变化记录在线程的Remembered Set Log,这里把Remembered Set Log合并到Remembered Set中;
需要"Stop The World",且停顿时间比初始标记稍长,但远比并发标记短;
采用多线程并行执行来提升效率。

(D)、筛选回收(Live Data Counting and Evacuation)
首先排序各个Region的回收价值和成本
然后根据用户期望的GC停顿时间来制定回收计划;
最后按计划回收一些价值高的Region中垃圾对象;
回收时采用**"复制"算法**,从一个或多个Region复制存活对象到堆上的另一个空的Region,并且在此过程中压缩和释放内存;
可以并发进行,降低停顿时间,并增加吞吐量;

收集器将整个Java堆划分成多个大小相等的Region
年轻代和老年代不再物理隔离 这时候不需要分配连续的内存空间

 

回顾关系图:

五、面试题总结

1.Object的finalize方法作用是否与C++的析构函数作用相同?

用于对象被垃圾回收时候 如果调用了会让被回收的对象再链接到GC ROOT上 得到一次重生的机会 不过不一定执行 可能没有执行完就被回收了
尽量不要使用
(1).对象不一定会被回收。
(2).垃圾回收不是析构函数。
(3).垃圾回收只与内存有关。
(4).垃圾回收和finalize()都是靠不住的,只要JVM还没有快到耗尽内存的地步,它是不会浪费时间进行垃圾回收的。

2.强引用 软引用 弱引用 虚引用 引用队列

(1)强引用(Strong Reference)

(2)软引用(Soft Reference)

(3)弱引用(Weak)

 

(4)虚引用(PhantomReference)


在这里插入图片描述

GC回收一个对象 会判断对象有没有虚引用 如果有回收之前会把虚引用放进引用队列 来跟踪对象是否被回收


在这里插入图片描述

  3.引用队列:

 

内存泄露与内存溢出

a)内存泄露:被分配对象可达但无用
b)内存溢出:无法申请到足够的内存而产生的错误

内存泄漏场景
a)创建和应用生命周期一样的单例对象
b)创建匿名内部类的静态对象
c)未关闭资源
d)长时间存在的集合容器中创建生命周期短的对象
e)修改hashset中的值,因此改变了该对象的哈希值

内存溢出场景
a)堆内存溢出
b)方法区内存溢出(反射,静态变量)
c)线程栈溢出(递归)

避免内存溢出
a)尽早释放无用内存
b)处理字符串尽可能使用StringBuffer,因为每创建一个String占一个独立内存
c)少用静态变量(JDK1.8不存在方法区,不用考虑)
d)避免循环中创建对象

 

 

六、全文回顾

判断标准:

不再被引用的对象就会成为垃圾

 

标记垃圾的算法:

引用收集器算法和可达性算法

 

回收垃圾的算法:

标记清理算法

复制算法

标记整理算法

主流的分代收集算法

 

GC的分类:

minorGC

FULL GC

年轻代的垃圾收集

年轻代内存块的划分

以及Eden和两个servivor区是如何做minorGC的

 

从年轻代晋升到老年代的条件

 

常用的调优参数

调整Eden和servivor比值的参数

调整年轻代和老年代比例的参数

对象从年轻代晋升到老年代需要经过的次数

 

老年代的垃圾收集

使用标记清理

或者标记整理

 

触发FULL GC的条件

 

什么是stop the world

 

什么是safe point

 

常见的垃圾收集器:

JVM运行模式的副本:

Client 和Server

可以通过java –version去查询当前使用的虚拟机模式

 

年轻代的三个收集器

 

老年代的垃圾收集器

一些是以减少stop the world ,另一些是增大吞吐量

 

垃圾收集器之间的关系

 

常见面试题

Finalize

Java的4种引用

ReferenceQueue的作用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IMUHERO

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值