• 聊聊Java的垃圾回收机制



    前言

    垃圾回收机制是JVM中非常重要的知识点,也是面试的高频问题。这篇文章就来简单的探讨一下有关JAVA中的垃圾回收的问题,包括堆的分区、垃圾回收算法等。


    一、堆的分区

    前面提到了堆分了新生代和老年代,新生代又分为eden和survivor区,survivor区又分为from和to区。
    在这里插入图片描述
    垃圾回收主要在堆中进行,介绍完堆的分区之后,就可以开始进入今天的主题了。
    以往我们编写程序时候,经常会创建很多对象,但我们从未对这些对象进行回收,那么是谁帮我们完成了对象的回收呢?
    答案:JVM帮我们做了(自动回收垃圾)
    垃圾是什么:只要对象不再被使用了,那我们就可以认为该对象就是垃圾,对象所占用的空间就可以被回收。

    判断对象是否为垃圾有两个常见的算法:引用计数法和可达性分析法(之前的文章已经介绍,本文不再叙述)

    JVM用的就是可达性分析算法来判断对象是否是垃圾,它从GC Roots开始向下搜索,当对象到GC Roots都没有任何引用相连时,说明对象是不可用的,可以被回收。

    哪些可以作为GC Roots?
    Java线程当前活跃的栈帧里指向GC堆里的对象的引用,GC Root 需要确保引用所指的对象都是活着的,而当前线程栈帧中的对象,在这一时刻是存活的。


    二、垃圾回收算法

    垃圾回收的第一步就是标记,标记哪些没有被「GC Roots」引用的对象
    在这里插入图片描述

    2.1标记清除算法和标记复制算法

    标记清除算法:最简单残暴的算法,直接将垃圾干掉。但存在内存碎片的问题。
    内存碎片:可能有10M的空余内存,但程序申请9M内存空间却申请不下来(10M的内存空间是垃圾清除后的,不连续的)。
    在这里插入图片描述
    那么有什么算法可以解决内存碎片问题呢?
    标记复制算法:把存活的对象复制到另一块空间,复制完了之后,直接把原有的整块空间给干掉,这样就没有内存碎片的问题。但这又会有很多缺点:内存利用率低,得有一块新的区域给复制(移动)过去。

    2.2标记整理算法

    标记整理算法:把存活的对象移到一边,把垃圾移到一边,那再将垃圾一起删除掉。
    在这里插入图片描述
    下面用一张表来总结一下三种回收算法的特点:
    在这里插入图片描述


    三、为什么要分代

    由于大部分对象的生命周期都很短,而只有少部分对象可能会存活很长时间。
    年轻代特点:区域相对老年代较小,对象生命周期短、存活率低,回收频繁,适合标记复制算法。

    老年代特点:区域较大,对象生命周期长、存活率高,回收不及年轻代频繁。这种情况存在大量存活率高的对象,复制算法明显变得不合适。一般是由标记- 清除或者是标记-清除与标记-整理的混合实现。

    stop the world(应用停止访问):回收垃圾的时候,程序是有短暂的时间不能正常继续运作。
    又由于垃圾回收是会导致stop the world,所以分代的一个原因是为了使stop the world持续的时间尽可能短。

    总结:不同生命周期的对象可以采取不同的收集方式,以便提高回收效率。一般是把 Java 堆分为新生代和老年代,这样就可以根据各个年代的特点使用不同的回收算法, 以提高垃圾回收的效率,同时使stop the world持续的时间尽可能短。


    总结

    本文主要介绍了几种常见的垃圾回收算法,每种算法各有利弊,不存在谁比谁好的说法。介绍了垃圾回收为什么要进行分代,一是为了提高垃圾回收的效率,二是尽可能的使STW的时间尽可能的短。


  • 相关阅读:
    编译原理复习——语法分析(自顶向下)
    LeetCode每日一题——2678. Number of Senior Citizens
    ubuntu部署k8s
    如何在Firefox中配置HTTP?
    猿创征文|开源监控软件Zabbix6部署实战
    实战Kafka的部署
    【python基础3】
    leetcode每天5题-Day31
    解决git中出现的“fatal ‘xxxx‘ does not appear to be a git repository”错误的方法
    青源Talk第8期|苗旺:因果推断,观察性研究和2021年诺贝尔经济学奖
  • 原文地址:https://blog.csdn.net/qq_52173163/article/details/125478616