垃圾回收知识整理

1.为什么要有垃圾回收

提高开发效率:程序员无需显式地分配和释放内存,这是由Java虚拟机(JVM)自动处理的。这种自动内存管理大大简化了程序员的工作。

减少程序错误: 手动管理内存致各种内存管理错误(如内存泄漏、野指针等)导致的程序崩溃。

避免内存泄漏: 手动管理内存程序员需显式地分配和释放内存,如果程序员忘记释放内存就会导致内存泄漏。

2.垃圾回收主要回收哪个内存区域

jvm内存划分 程序计数器 栈 方法区 堆

程序计数器不需要GC 

栈中存放的主要是局部变量 局部变量都是在代码块执行结束后自动销毁 不需要GC

方法区一般不需要GC  一般是涉及类加载 很少涉及类卸载

堆中主要存放的是new出来的对象 是GC的主战场

3.检测垃圾

1) 使用计数

给对象增加⼀个引⽤计数器,每当有⼀个地⽅引⽤它时,计数器就+1;当引⽤失效时,计数器就-1;
任何时刻计数器为0的对象就是不能再被使⽤的,即对象已"死"。
引⽤计数法实现简单,判定效率也⽐较⾼,在⼤部分情况下都是⼀个不错的算法。⽐如Python语⾔就采⽤引⽤计数法进⾏内存管理。

这个机制存在两个关键的问题

a)消耗额外的空间

要给每个对象安排一个计数器,(如果计数器按照2个字节) 如果整个程序对象很多,总的消耗也会很大

尤其是当对象所占的内存比较小,计数器消耗的空间,已经达到对象所占空间的一半了

b)引用计数可能产生"循环引用的问题" 此时 ,引用计数就无法正常工作

在主流的JVM中没有选⽤引⽤计数法来管理内存,最主要的原因就是引⽤计数法⽆法解决对象的循环引⽤问题

2)可达性分析

通过⼀系列称为"GC Roots"的对象作为起始点,从这些节点开始向下搜索,搜索⾛过的路径称之为"引⽤链",当⼀个对象到GC Roots没有任何的引⽤链相连时(从GC Roots到这个对象不可达)时,证明此对象是不可⽤的。

 对象ObjectE-ObjectG之间虽然彼此还有关联,但是它们到GC Roots是不可达的,因此他们会被判定为可回收对象。

在Java语⾔中,可作为GC Roots的对象包含下⾯⼏种:
1. 虚拟机栈(栈帧中的本地变量表)中引⽤的对象;
2. ⽅法区中类静态属性引⽤的对象;
3. ⽅法区中常量引⽤的对象;
4. 本地⽅法栈中JNI(Native⽅法)引⽤的对象

只有从GC Roots对象开始,通过引用链可达的对象才被认为是存活的,而无法通过引用链访问的对象则会被判定为垃圾,并进行回收。

缺点:

遍历开销:可达性分析算法需要遍历整个对象图以确定每个对象的可达性。对于大型堆和复杂的引用关系,遍历开销可能非常大,特别是在全局垃圾回收中。这可能会导致垃圾回收的性能下降。
延迟回收:可达性分析算法需要遍历整个对象图,从GC Roots开始,逐个检查每个对象的引用关系。这个过程可能需要消耗大量的时间,且在垃圾回收期间,应用程序的执行会被暂停(STW - Stop-The-World)。因此,可达性分析算法可能导致较高的延迟,影响程序的响应性能。

4.回收垃圾

a)标记-清除算法

"标记-清除"算法是最基础的收集算法。算法分为"标记"和"清除"两个阶段:⾸先标记出所有需要回收
的对象,在标记完成后统⼀回收所有被标记的对象,后续的收集算法都是基于这种思路并对其不⾜加以改进⽽已。
"标记-清除"算法的不⾜主要有两个:

1. 效率问题:标记和清除这两个过程的效率都不⾼
2. 空间问题:标记清除后会产⽣⼤量不连续的内存碎⽚,空间碎⽚太多可能会导致以后在程序运⾏中需要分配较⼤对象时,⽆法找到⾜够连续内存⽽不得不提前触发另⼀次垃圾收集。

b)复制算法

"复制"算法是为了解决"标记-清理"的效率问题。它将可⽤内存按容量划分为⼤⼩相等的两块,每次只使⽤其中的⼀块。当这块内存需要进⾏垃圾回收时,会将此区域还存活着的对象复制到另⼀块上⾯,然后再把已经使⽤过的内存区域⼀次清理掉。这样做的好处是每次都是对整个半区进⾏内存回收,内存分配时也就不需要考虑内存碎⽚等复杂情况,只需要移动堆顶指针,按顺序分配即可。此算法实现简单,运⾏⾼效。

缺点:

内存利用率比较低。

如果当前区域的大部分对象都需要保留垃圾很少,那么此时的复制成本就比较高

c)标记-整理算法

复制收集算法在对象存活率较⾼时会进⾏⽐较多的复制操作,效率会变低。因此在⽼年代⼀般不能使⽤复制算法。
针对⽼年代的特点,提出了⼀种称之为"标记-整理算法"。标记过程仍与"标记-清除"过程⼀致,但后续步骤不是直接对可回收对象进⾏清理,⽽是让所有存活对象都向⼀端移动,然后直接清理掉端边界以外的内存。

d)分代算法

分代算法是通过区域划分,实现不同区域和不同的垃圾回收策略,从⽽实现更好的垃圾回收。

当前JVM垃圾收集都采⽤的是"分代收集(Generational Collection)"算法,这个算法并没有新思想,只是根据对象存活周期的不同将内存划分为⼏块。⼀般是把Java堆分为新⽣代和⽼年代。在新⽣代中,每次垃圾回收都有⼤批对象死去,只有少量存活,因此我们采⽤复制算法;⽽⽼年代中对象存活率⾼、没有额外空间对它进⾏分配担保,就必须采⽤"标记-清理"或者"标记-整理"算法。

哪些对象会进⼊新⽣代?哪些对象会进⼊⽼年代?

• 新⽣代:⼀般创建的对象都会进⼊新⽣代;
• ⽼年代:⼤对象和经历了N次(⼀般情况默认是15次)垃圾回收依然存活下来的对象会从新⽣代移动到⽼年代。

5.垃圾回收器有哪些典型实现?

1)Serial收集器(新⽣代收集器,串⾏GC)

Serial收集器是最基本、发展历史最悠久的收集器,曾经(在JDK1.3.1之前)是虚拟机新⽣代收集的唯⼀选择。

• 特性:

这个收集器是⼀个单线程的收集器,但它的“单线程”的意义并不仅仅说明它只会使⽤⼀个CPU或
⼀条收集线程去完成垃圾收集⼯作,更重要的是在它进⾏垃圾收集时,必须暂停其他所有的⼯作线
程,直到它收集结束(Stop The World,译为停⽌整个程序,简称STW)。

b)ParNew收集器(新⽣代收集器,并⾏GC)

ParNew收集器其实就是Serial收集器的多线程版本,除了使⽤多条线程进⾏垃圾收集之外,其余⾏为包括Serial收集器可⽤的所有控制参数、收集算法、Stop The World、对象分配规则、回收策略等都与Serial收集器完全⼀样,在实现上,这两种收集器也共⽤了相当多的代码。

• 特性:

Serial收集器的多线程版本

c)Parallel Scavenge收集器(新⽣代收集器,并⾏GC)

• 特性:

Parallel  Scavenge收集器是⼀个新⽣代收集器,它也是使⽤复制算法的收集器,⼜是并⾏的

多集器。

d)Serial Old收集器(⽼年代收集器,串⾏GC)

• 特性:

Serial Old是Serial收集器的⽼年代版本,它同样是⼀个单线程收集器,使⽤标记-整理算法。

e)Parallel Old收集器(⽼年代收集器,并⾏GC)

• 特性:

Parallel Old是Parallel Scavenge收集器的⽼年代版本,使⽤多线程和**“标记-整理”**算法。

f)CMS收集器(⽼年代收集器,并发GC)

• 特性:

CMS(Concurrent Mark Sweep)收集器是⼀种以获取最短回收停顿时间为⽬标的收集器。⽬前很⼤⼀部分的Java应⽤集中在互联⽹站或者B/S系统的服务端上,这类应⽤尤其重视服务的响应速度,希望系统停顿时间最短,以给⽤⼾带来较好的体验。CMS收集器就⾮常符合这类应⽤的需求。

CMS收集器是基于“标记—清除”算法实现的,它的运作过程相对于前⾯⼏种收集器来说更复杂⼀
些,整个过程分为4个步骤:

• 初始标记(CMS initial mark)
初始标记仅仅只是标记⼀下GC Roots能直接关联到的对象,速度很快,需要“Stop The World”。
• 并发标记(CMS concurrent mark)
并发标记阶段就是进⾏GC Roots Tracing的过程。
• 重新标记(CMS remark)
重新标记阶段是为了修正并发标记期间因⽤⼾程序继续运作⽽导致标记产⽣变动的那⼀部分对象的标记记录,这个阶段的停顿时间⼀般会⽐初始标记阶段稍⻓⼀些,但远⽐并发标记的时间短,仍然需要“Stop The World”。
• 并发清除(CMS concurrent sweep)
并发清除阶段会清除对象。

g)G1收集器(唯⼀⼀款全区域的垃圾回收器)

G1(Garbage First)垃圾回收器是⽤在heap memory很⼤的情况下,把heap划分为很多很多的region块,然后并⾏的对其进⾏垃圾回收。

G1垃圾回收器在清除实例所占⽤的内存空间后,还会做内存压缩。

G1垃圾回收器回收region的时候基本不会STW,⽽是基于most garbage优先回收(整体来看是基于"标记-整理"算法,从局部(两个region之间)基于"复制"算法)的策略来对region进⾏垃圾回收的。⽆论如何,G1收集器采⽤的算法都意味着⼀个region有可能属于Eden,Survivor或者Tenured内存区域。图中的E表⽰该region属于Eden内存区域,S表⽰属于Survivor内存区域,T表⽰属于Tenured内存区域。图中空⽩的表⽰未使⽤的内存空间。G1垃圾收集器还增加了⼀种新的内存区域,叫做Humongous内存区域,如图中的H块。这种内存区域主要⽤于存储⼤对象-即⼤⼩超过⼀个region⼤⼩的50%的对象

相关推荐

  1. lua gc垃圾回收知识记录

    2024-04-22 16:58:08       20 阅读
  2. 面试知识汇总——垃圾回收器(G1垃圾回收器)

    2024-04-22 16:58:08       16 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-04-22 16:58:08       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-04-22 16:58:08       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-04-22 16:58:08       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-04-22 16:58:08       20 阅读

热门阅读

  1. JDK中用到了哪些设计模式

    2024-04-22 16:58:08       32 阅读
  2. npm 常用命令详解

    2024-04-22 16:58:08       39 阅读
  3. flask 请求对象

    2024-04-22 16:58:08       54 阅读
  4. 分组带给了我们哪些?

    2024-04-22 16:58:08       36 阅读
  5. Elasticsearch:(二)3.安装Elasticsearch-head插件

    2024-04-22 16:58:08       39 阅读
  6. linux 查看nginx日志

    2024-04-22 16:58:08       19 阅读
  7. 聚类与分类的区别

    2024-04-22 16:58:08       31 阅读
  8. 【运维基础一】 Linux Centos 常用命令

    2024-04-22 16:58:08       43 阅读
  9. https通信流程

    2024-04-22 16:58:08       58 阅读
  10. 「Python大数据」数据采集-某东产品数据评论获取

    2024-04-22 16:58:08       15 阅读