Java-垃圾回收机制

前言

天将降大任于斯人也,必先苦其心志,劳其筋骨,饿其体肤,空乏其身。
知识就像甘蔗,入口甘甜,嚼之清脆爽口,久了不知其味,弃之又觉可惜,唯有反复咀嚼,方可有所增益,他日终成正果~
画风一转,来谈一谈Java垃圾回收。本文将围绕以下三个问题来进行讲解。
在这里插入图片描述

  1. 如何判断需要回收的内存?
  2. 什么时候回收内存?
  3. 如何回收内存?

简介

Java 中的内存分为堆(Heap)和栈(Stack)两部分,其中堆用于存储对象,栈用于存储基本类型数据和对象引用。Java 垃圾回收机制会自动回收不再使用的堆内存,以避免内存泄漏和内存溢出等问题。

Java 中的内存回收通常有以下情况:
当一个对象没有任何引用指向它时,即该对象变为孤岛状态时,Java 的垃圾回收机制会将其标记为可回收对象,等待下一次垃圾回收。

当堆内存空间不足或无法满足对象需要时,Java 的垃圾回收机制会启动,并扫描堆内存中的对象,识别并释放那些可回收的对象,从而腾出更多的内存空间。

当Java虚拟机关闭时,所有内存都会被回收。

需要注意的是,Java 垃圾回收机制并不保证立即回收内存,因此在某些情况下,可能需要手动调用 System.gc() 方法来触发垃圾回收机制。另外,如果程序中存在大量的临时对象或长时间占用的对象,也可能会导致内存过度消耗,从而影响系统的性能和稳定性。

因此,在Java中,开发人员需要注意内存管理,避免内存泄漏和内存溢出等问题,提高程序的性能和可靠性。

判断对象是否存活的算法

引用计数算法(Reference Counting)

•算法分析
引用计数是垃圾收集器中的早期策略,它的原理是给对象添加一个引用计数器,每当一个地方引用它时,计数器值就加1;让引用失效时,计数器值就减1;任何时刻计数器为0的对象是不可能再被使用的。

•优点
引用计数收集器可以很快的执行,交织在程序运行中。对程序需要不被长时间打断的实时环境比较有利。

•缺点
无法检测出循环引用。如父对象有一个对子对象的引用,子对象反过来引用父对象。这样,他们的引用计数永远不可能为0。 引用计数算法无法解决循环引用问题,例如:

public class Main {    
       public static void main(String[] args) {
            MyObject object1 = new MyObject();        
            MyObject object2 = new MyObject();

            object1.object = object2;        
            object2.object = object1;

            object1 = null;        
            object2 = null;

           //假设在这行发生GC,object1和object2能否被回收?          
            System.gc();    
      }
 }
 
最后面两句将object1和object2赋值为null,也就是说object1和object2指向的对象已经不可能再被访问,但是由于它们互相引用对方,导致它们的引用计数器都不为0,那么垃圾收集器就永远不会回收它们。

可达性分析算法(Reachability Analysis)

•算法分析
通过一系列称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路称为引用链(Refence Chain),当一个对象到GC Roots没有任何链表相连(用图论的话来说,就是GC Roots到这个对象不可达)时,则证明此对象不可用。

Java中可作为GC Roots的对象有
1.虚拟机栈中引用的对象(本地变量表)
2.方法区中静态属性引用的对象
3. 方法区中常量引用的对象
4.本地方法栈中引用的对象(Native对象)

如图所示:
可达性算法分享

垃圾回收算法

标记-清除算法

•算法分析
最基础的垃圾收集算法,算法分为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,在标记完成之后统一回收掉所有被标记的对象。

•优点
原理简单,易于操作

•缺点
效率低
标记和清除的效率都不高

内存碎片
标记清除后会产生大量不连续的内存碎片,内存碎片太多会导致当程序需要分配较大的对象时,无法找到足够的连续内存而不得不提前触发 GC

在这里插入图片描述

复制算法

为了解决效率问题,复制(Copying)收集算法出现了。
•算法分析
复制算法把可用内存按容量划分为大小相等的两块,每次只使用其中的一块。
当使用中的这块内存用完了,就把存活的对象复制到另一块内存上,然后把已使用的空间一次清理掉。
这样每次都是对半个内存区域进行回收,内存分配时也不用考虑内存碎片等复杂问题。

•优点
复制算法的优点是每次只对半个内存区域进行内存回收,分配内存时也不用考虑内存碎片等复杂情况,只要一动堆顶指针,按顺序分配内存即可。

•缺点
浪费空间,把内存缩小一半来使用太浪费空间。

有时效率较低,在对象存活率高时,要进行较多的复制操作,这时效率就变低了
在这里插入图片描述

标记-整理算法

•算法分析
标记-整理算法在标记-清除算法基础上进行改进,先将所有需要回收的对象进行标记,标记完成之后不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,在移动过程中清理掉可回收的对象,这个过程称为标记-整理。

•优点
内存被整理以后不会产生大量不连续内存碎片问题。

•缺点
复制算法在对象存活率高的情况下就要执行较多的复制操作,效率将会变低,而在对象存活率低的情况下使用标记-整理算法效率会大大提高。

在这里插入图片描述

分代收集算法

•算法分析
根据内存中对象的存活周期不同,将内存划分为几块,java的虚拟机中一般把内存划分为新生代和年老代,当新创建对象时一般在新生代中分配内存空间,当新生代垃圾收集器回收几次之后仍然存活的对象会被移动到年老代内存中,当大对象在新生代中无法找到足够的连续内存时也直接在年老代中创建。

分代的垃圾回收策略,是基于这样一个事实:不同的对象的生命周期是不一样的。因此,不同生命周期的对象可以采取不同的回收算法,以便提高回收效率。
在这里插入图片描述
在这里插入图片描述
•年轻代(Young Generation)
1.所有新生成的对象首先都是放在年轻代的。年轻代的目标就是尽可能快速的收集那些生命周期短的对象。

2.新生代内存按照8:1:1的比例分为一个eden区和两个survivor(survivor0,survivor1)区。一个Eden区,两个 Survivor区(一般而言)。大部分对象在Eden区中生成。回收时先将eden区存活对象复制到一个survivor0区,然后清空eden区,当这个survivor0区也存放满了时,则将eden区和survivor0区存活对象复制到另一个survivor1区,然后清空eden和这个survivor0区,此时survivor0区是空的,然后将survivor0区和survivor1区交换,即保持survivor1区为空, 如此往复。

3.当survivor1区不足以存放 eden和survivor0的存活对象时,就将存活对象直接存放到老年代。若是老年代也满了就会触发一次Full GC,也就是新生代、老年代都进行回收

4.新生代发生的GC也叫做Minor GC,MinorGC发生频率比较高(不一定等Eden区满了才触发)

•老年代(Old Generation)

1.在年轻代中经历了N次垃圾回收后仍然存活的对象,就会被放到年老代中。因此,可以认为年老代中存放的都是一些生命周期较长的对象。

2.内存比新生代也大很多(大概比例是1:2),当老年代内存满时触发Major GC即Full GC,Full GC发生频率比较低,老年代对象存活时间比较长,存活率标记高。、

•持久代(Permanent Generation)

用于存放静态文件,如Java类、方法等。持久代对垃圾回收没有显著影响,但是有些应用可能动态生成或者调用一些class,例如Hibernate 等,在这种时候需要设置一个比较大的持久代空间来存放这些运行过程中新增的类。

垃圾收集器

新生代收集器:Serial、ParNew、Parallel Scavenge
老年代收集器:Serial Old、Parallel Old 、CMS
整堆收集器: G1

Serial 收集器:该收集器是单线程的,适用于内存较小的环境和客户端应用程序。在进行垃圾回收时,暂停所有用户线程,执行复制算法/标记-清除算法。

Parallel 收集器:该收集器是多线程的,并行处理垃圾回收任务,适用于高性能服务器应用程序。在执行垃圾回收时,会使用复制算法/标记-清除算法,以提高效率和吞吐量。

CMS(Concurrent Mark and Sweep)收集器:该收集器是并发执行的,适用于对响应时间有严格要求的应用程序。在执行垃圾回收时,避免了长时间的暂停,使用标记-清除算法

G1(Garbage-First)收集器:该收集器是一种分代收集器,适用于大型堆内存环境下的高性能应用程序。它使用了多个 CPU 核心和多个并发线程来执行垃圾回收任务,采用了复制算法和标记-整理算法,以优化性能和吞吐量。
在这里插入图片描述
在这里插入图片描述

总结

总而言之,集百家之所长,因势利导,合理分配,有所分工,一起走向“共同富裕”。
在这里插入图片描述

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值