JVM:自动垃圾回收

news/2024/8/28 1:13:29 标签: jvm, java, 算法

文章目录

  • 一、C/C++的内存管理
  • 二、Java的内存管理
    • 1、方法去的回收
    • 2、堆回收
      • (1)引用计数法和可达性分析法
      • (2)五种对象引用
      • (3)垃圾回收算法

一、C/C++的内存管理

  • 在C和C++没有自动垃圾回收机制,一个对象如果不在使用需用手动释放,否则会出现内存泄漏。
  • 内存泄漏指的是不再使用的对象在系统中未被回收,内存泄漏的积累可能会导致内存溢出。

二、Java的内存管理

Java为了简化对象释放,引入了自动的垃圾回收(Garbage Collection简称GC)机制。通过垃圾回收器来对不再使用的对象完成自动的回收,垃圾回收器主要负责对堆上的内存进行回收。其他很多现代语言比如C#、Python、Go都拥有自己的垃圾回收器。

1、方法去的回收

方法区中能回收的内容主要是不再使用的类。判定一个类可以被卸载,需要同时满足下面三个条件:

  • 此类所有实例对象都已经被回收,在堆中不存在任何该类的实例对象以及子类对象。
  • 加载该类的类加载器已经被回收。
  • 该类对应的java.lang.Class对象没有任何地方被引用。

手动触发回收

  • 如果需要手动触发垃圾回收,可以调用System.gc()方法。
  • 语法:System.gc()。
  • 注意事项:调用System.gc()方法并不一定会立即回收垃圾,仅仅是向Java虚拟机发送一个垃圾回收的请求,具体是否需要执行垃圾回收Java虚拟机会自动判断。

打印类的加载和卸载信息配置:

  • -XX:+TraceClassLoading
  • -XX:+TraceClassUnloading

2、堆回收

Java中对象是否能被回收,是根据对象是否被引用来决定的。如果对象被引用了,说明改对象还在使用,不允许被回收。只有无法通过引用获取到对象时,该对象才能被回收。

  • -verbose:gc打印垃圾回收日志

(1)引用计数法和可达性分析法

引用计数法

  • 引用计数法会为每个对象维护一个引用计数器,当对象被引用时加1,取消引用时减1。引用计数法的优点是实现简单,C++中的智能指针就采用了引用计数法,但是它也存在缺点,主要有两点:
  • 每次引用和取消引用都需要维护计数器,对系统性能会有一定的影响。
  • 存在循环引用问题,所谓循环引用就是当A引用B,B同时引用A时会出现对象无法回收的问题。

可达性分析法

  • Java使用的是可达性分析算法来判断对象是否可以被回收。可达性分析将对象分为两类:垃圾回收的根对象(GC Root)和普通对象,对象与对象之间存在引用关系。
  • 哪些对象可以作为GC Root:
    • 线程Thread对象,引用线程栈帧中的方法参数、局部变量等。
    • 系统类加载器加载的java.lang.Class对象。
    • 监视器对象,用来保存同步锁synchronized关键字持有的对象。
    • 本地方法调用时使用的全局对象。

查看GC Root
通过arthas和eclipse Memory Analyzer(MAT)工具可以查看GC Root,MAT工具是eclipse推出的Java堆内存检测工具。具体操作步骤如下:

  • 使用arthas的heapdump命令将堆内存快照保存到本地磁盘中。
  • 使用MAT工具打开堆内存快照文件。
  • 选择GC Roots功能查看所有的GC Root。
    在这里插入图片描述

(2)五种对象引用

可达性算法中描述的对象引用,一般指的是强引用,即是GC Root对象堆普通对象有引用关系,只要这层关系存在,普通对象就不会被回收。除了强引用之外,Java中还设计了几种其他引用方式:

  • 软引用
    软引用相对于强引用时一种比较弱的引用关系,如果一个对象只有软引用关联到它,当程序内存不足时,就会将软引用中的数据进行回收。在JDK1.2版本之后提供了SoftReference类来实现软引用,软引用常用于缓存中。执行过程如下:
    • 将对象使用软引用包装起来,new SoftReference<对象类型>(对象)。
    • 内存不足时,虚拟机尝试进行垃圾回收。
    • 如果垃圾回收仍不能解决内存不足的问题,回收软引用中的对象。
    • 如果仍然内存不足,抛出OutOfMemory异常。

软引用中的对象如果在内存不足时回收,SoftReference对象本身也需要被回收。如何知道哪些SoftReference对象需要回收呢,SoftReference提供了一套队列机制:

  • 软引用创建时,通过构造器传入引用队列。

  • 在软引用中包含的对象被回收时,该软引用对象会被放入引用队列。

  • 通过遍历引用队列,将SoftRference的强引用删除。

  • 弱引用
    包含的对象在垃圾回收时,不管内存够不够都会直接被回收。在JDK1.2版本之后提供了WeakReference类来实现弱引用,弱引用主要在ThreadLocal中使用。弱引用本身也可以使用引用队列进行回收。

  • 虚引用
    虚引用也叫幽灵引用/幻影引用,不能通过虚引用对象获取到包含的对象。虚引用唯一的用途是当对象被垃圾回收器回收时可以接收到对应的通知。Java中使用PhantomReference实现了虚引用,直接内存中为了及时知道直接内存对象不在使用,从而回收内存,使用了虚引用来实现。

  • 终结器引用
    指的是对象需要被回收时,对象将会被放置在Finalizer类中的引用队列中,并在稍后由一条由FinalizerThread线程从队列中获取对象,然后执行对象的finalize方法。在这个过程中可以在finalize方法中再将自身对象使用强引用关联上,但是不建议这样做,如果耗时过长会影响其他对象的回收。

(3)垃圾回收算法

垃圾回收算法的历史和分类

  • 1960年John McCarthy发布了第一个GC算法:标记-清除算法
  • 1963年Marvin L.Minsky发布了复制算法
    本质上后续所有的垃圾回收算法,都是在上述两种算法的基础上优化而来。
    在这里插入图片描述
    Java垃圾回收过程会通过单独的GC线程来完成,但是不管使用哪种GC算法,都会有部分阶段需要停止所有的用户线程。这个过程被称为Stop The World简称STW,如果STW时间过程则会影响用户的使用。

垃圾回收算法的评价标准

  • 吞吐量

    • 吞吐量值得是CPU用于执行用户代码的时间与CPU总执行的时间比值。吞吐量越高,垃圾回收的效率越高。
  • 最大停顿时间

    • 指的是垃圾回收过程中STW时间最大值。

标记清除算法

  • 标记阶段,将所有存活的对象进行标记。Java中使用可达性分析算法,从GC Root开始通过引用链遍历出所有存活对象。
  • 清除阶段,从内存中删除没有被标记也就是非存活对象。
  • 优点:实现简短,缺单:碎片会问题。

复制算法的核心思想
准备两块空间From空间和同空间,每次兑现分配阶段,只能使用其中一块空间(From 空间)。

  • 在垃圾回收GC阶段,将From中存活的对象复制到To空间。
  • 将两块内存空间的From和To名字互换。
  • 优点
    • 吞吐量高:只需要遍历一次存活对象。
    • 不会发生碎片化。
  • 缺点
    • 内存使用率低。

标记整理算法
标记整理算法也叫标记压缩算法,是对标记整理算法中容易产生内存碎片问题的一种解决方案。核心思想:

  • 标记阶段,将所有存活对象进行标记(采用可达性分析算法)。
  • 整理阶段,将存活对象移动到堆的一端。进行清理操作。
  • 优点
    • 吞吐量高:只需要遍历一次存活对象。
    • 不会发生碎片化。
  • 缺点
    • 整理阶段效率不高。

分代垃圾回收算法
将整个内存区域划分为年轻代(存活时间比较短的对象)和老年代(存放时间比较长的对象)。

  • 在JDK8,添加-XX:+UseSerialGC参数使用分代回收的垃圾回收器,运行程序。
  • 在arthas中使用memory命令查看内存,显示出三个区域的内存情况。
    在这里插入图片描述
    分代回收时,创建出来的对象,首先会被放入Eden伊甸园区。随着对象在Eden区越来越多,如果Eden区满,新创建的对象已经无法放入,就会触发年轻代的GC,称为Minor GC或者Young GC。Minor GC会把需要eden中和From需要回收的对象回收,把没有回收的对象放入To区。如果Minor GC后对象的年龄达到阈值(最大15,默认值和垃圾回收器有关),对象就会被晋升至老年代。当老年代中空间不足,无法放入新的对象时,先尝试minor gc如果还是不足,就会触发Full GC,Full GC会对整个堆进行垃圾回收。

调整内存区域的大小
根据以下虚拟机参数,调整堆的大小并观察结果。注意加上-XX:+UseSerialGC
在这里插入图片描述


http://www.niftyadmin.cn/n/5559798.html

相关文章

XML 验证器:确保数据完整性和准确性的关键工具

XML 验证器&#xff1a;确保数据完整性和准确性的关键工具 引言 在当今数字化时代&#xff0c;数据的有效管理和交换至关重要。XML&#xff08;可扩展标记语言&#xff09;作为一种用于存储和传输数据的语言&#xff0c;广泛用于各种应用程序和系统之间。为确保XML数据的完整…

springcloud2021.x使用nacos做配置中心

spirngcloud2021.0.5使用nacos做配置中心遇到的问题 环境 jdk1.8&#xff0c;spring-boot 2.6.13&#xff0c;spring-cloud-alibaba 2021.0.5.0 &#xff0c;spring-cloud 2021.0.5 方案一 application.properties # Nacos帮助文档: https://nacos.io/zh-cn/docs/concepts…

C语言 | Leetcode C语言题解之第237题删除链表中的节点

题目&#xff1a; 题解&#xff1a; /*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/void deleteNode(struct ListNode* node) {struct ListNode * p node->next;int temp;temp node->val;node->val…

【MATLAB库函数系列】MATLAB库函数pwelch之功率谱估计的详解及实现

功率谱估计 由于实际信号通常是非定常的,我们只能假设其在10ms的时间段内是定常的,并在此基础上对短的定常信号求PSD或者能谱。 窗函数的作用就是将原始的信号分割成一段段可以计算PSD和能谱的短信号,并且保证了周期结构的连续性、避免了频谱泄漏。不同的窗函数具有不同的…

论文复现丨物流中心选址问题:蜘蛛猴算法求解

路径优化系列文章&#xff1a; 1、路径优化历史文章2、物流中心选址问题论文复现丨改进蜘蛛猴算法求解 物流中心选址问题 一般物流中心选址问题是指&#xff1a;在有限的用户(即需求点)中找出一定数量的地点建立配送中心&#xff0c;实现从物流中心到用户之间的配送&#xf…

Spring:SpringBoot为什么可以使用Jar包启动

SpringBoot 之所以可以使用 Jar 包启动&#xff0c;主要得益于其内置的 Spring Boot Maven 或 Gradle 插件&#xff0c;这些插件在打包过程中进行了一系列的特殊处理&#xff0c;使得打包出来的 Jar 文件不仅仅包含了应用的代码和资源&#xff0c;还包含了所有必需的依赖库&…

快速排序及归并排序的实现与排序的稳定性

目录 快速排序 一. 快速排序递归的实现方法 1. 左右指针法 步骤思路 为什么要让end先走&#xff1f; 2. 挖坑法 步骤思路 3. 前后指针法 步骤思路 二. 快速排序的时间和空间复杂度 1. 时间复杂度 2. 空间复杂度 三. 快速排序的优化方法 1. 三数取中优化 2. 小区…

.net core appsettings.json 配置 http 无法访问

1、在appsettings.json中配置"urls": "http://0.0.0.0:8188" 2、但是网页无法打开 3、解决办法&#xff0c;在Program.cs增加下列语句 app.UseAntiforgery();