jvm基础篇之垃圾回收[2](垃圾回收算法)

文章目录

  • 版权声明
  • 垃圾回收算法核心思想
  • 垃圾回收算法的历史
  • 垃圾回收算法的评价标准
  • 垃圾分类算法分类
    • 标记清除算法
      • 核心思想
      • 标记清除算法优缺点
    • 复制算法
      • 核心思想
      • 完整案例
      • 复制算法的优缺点
    • 标记整理算法
      • 核心思想
      • 标记整理算法优缺点
    • 分代垃圾回收算法
      • arthas查看分代内存情况
      • 核心思想
  • 虚拟机内存参数
    • StopWorldTest案例代码
    • GC案例1
    • GC案例2

版权声明

  • 本博客的内容基于我个人学习黑马程序员课程的学习笔记整理而成。我特此声明,所有版权属于黑马程序员或相关权利人所有。本博客的目的仅为个人学习和交流之用,并非商业用途。
  • 我在整理学习笔记的过程中尽力确保准确性,但无法保证内容的完整性和时效性。本博客的内容可能会随着时间的推移而过时或需要更新。
  • 若您是黑马程序员或相关权利人,如有任何侵犯版权的地方,请您及时联系我,我将立即予以删除或进行必要的修改。
  • 对于其他读者,请在阅读本博客内容时保持遵守相关法律法规和道德准则,谨慎参考,并自行承担因此产生的风险和责任。
  • 本博客中的部分观点和意见仅代表我个人,不代表黑马程序员的立场。

垃圾回收算法核心思想

  • 垃圾回收要做的有两件事:第一,找到内存中存活的对象;第二,释放不再存活对象的内存,使得程序能再次利用该空间
    在这里插入图片描述

垃圾回收算法的历史

在这里插入图片描述

  • 1960年John McCarthy发布了第一个GC算法:标记-清除算法
  • 1963年Marvin L. Minsky 发布了复制算法。
  • 本质上后续所有的垃圾回收算法,都是在上述两种算法的基础上优化而来

垃圾回收算法的评价标准

  • Java垃圾回收过程会通过单独的GC线程来完成。所有的GC算法,都会有部分阶段需要停止所有的用户线程,进行垃圾回收。这个过程被称之为Stop The World简称STW,如果STW时间过长则会影响用户的使用。
    在这里插入图片描述

垃圾回收算法的评价标准

  1. 吞吐量:吞吐量指的是 CPU 用于执行用户代码的时间与 CPU 总执行时间的比值,即 吞吐量 = 执行用户代码时间 / (执行用户代码时间 + G C 时间) 吞吐量 = 执行用户代码时间 /(执行用户代码时间 + GC时间) 吞吐量=执行用户代码时间/(执行用户代码时间+GC时间)
    • 吞吐量数值越高,垃圾回收的效率就越高.比如:虚拟机总共运行了 100 分钟,其中GC花掉 1 分钟,那么吞吐量就是 99%
  2. 最大暂停时间:最大暂停时间指的是所有在垃圾回收过程中的STW时间最大值。最大暂停时间越短,用户使用系统时受到的影响就越短。
    在这里插入图片描述
  3. 堆使用效率:不同垃圾回收算法,对堆内存的使用方式是不同的。比如标记清除算法,可以使用完整的堆内存。而复制算
    法会将堆内存一分为二,每次只能使用一半内存。从堆使用效率上来说,标记清除算法要优于复制算法
    在这里插入图片描述

  • ==上述三种评价标准:堆使用效率、吞吐量,以及最大暂停时间不可兼得。==一般来说,堆内存越大,最大暂停时间就越长。想要减少最大暂停时间,就会降低吞吐量。
  • 不同的垃圾回收算法,适用于不同的场景。没有最好的垃圾回收算法之说,只有不同场景下更合适的回收算法。

垃圾分类算法分类

标记清除算法

核心思想

  • 标记清除算法的核心思想分为两个阶段:第一标记阶段和第二清除阶段。
    1. 标记阶段,将所有存活的对象进行标记。Java中使用可达性分析算法,从GC Root开始通过引用链遍历出有存活对象。
    2. 清除阶段,从内存中删除没有被标记也就是非存活对象
      在这里插入图片描述

标记清除算法优缺点

  • 优点:实现简单,只需要在第一阶段给每个对象维护标志位,第二阶段删除对象即可
  • 缺点:碎片化问题;分配速度慢
    1. 碎片化问题:由于内存是连续的,在对象被删除后,内存中会出现很多细小的可用内存单元。对象需要一个比较大的空间,很有可能这些内存单元的大小过小无法进行分配。
      在这里插入图片描述
    2. 分配速度慢:由于内存碎片的存在,需要维护一个空闲链表,可能每次需要遍历到链表的最后才能获得合适的内存空间
      在这里插入图片描述

复制算法

核心思想

  • 复制算法的核心思想是:准备两块空间From空间和To空间,每次在对象分配阶段,只能使用其中一块空间(From空间)。在垃圾回收GC阶段,将From中存活对象复制到To空间。将两块空间的From和To名字互换。
    在这里插入图片描述

完整案例

完整的复制算法的例子:

  1. 将堆内存分割成两块From空间 To空间,对象分配阶段,创建对象
  2. GC阶段开始,将GC Root搬运到To空间
  3. 将GC Root关联的对象,搬运到To空间
  4. 清理From空间,并把名称互换
    在这里插入图片描述

复制算法的优缺点

  • 优点:吞吐量高、不会发生碎片化
    • 吞吐量高:复制算法只需遍历一次存活对象复制到To空间即可,比标记-整理算法少一次遍历的过程,因而性能较好,但是不如标记-清除算法,因为标记清除算法不需要进行对象的移动
    • 不会发生碎片化:复制算法在复制之后就会将对象按顺序放入To空间中,所以对象以外的区域都是可用空间,不存在碎片化内存空间
  • 缺点:内存使用效率低
    • 每次只能让一半的内存空间来为创建对象使用

标记整理算法

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

核心思想

  • 核心思想分为两个阶段:标记阶段和整理阶段
    1. 标记阶段,将所有存活的对象进行标记。Java中使用可达性分析算法,从GC Root开始通过引用链遍历出所有存活对象
    2. 整理阶段,将存活对象移动到堆的一端。清理掉存活对象的内存空间。
      在这里插入图片描述

标记整理算法优缺点

  • 优点:内存使用效率高、不会发生碎片化
    • 内存使用效率高:整个堆内存都可以使用,不会像复制算法只能使用半个堆内存
    • 不会发生碎片化:在整理阶段可以将对象往内存的一侧进行移动,剩下的空间都是可以分配对象的有效空间
  • 缺点:整理阶段效率不高
    • 整理算法有很多种,比如Lisp2整理算法需要对整个堆中的对象搜索3次,整体性能不佳。可以通过TwoFinger、表格算法、ImmixGC等高效的整理算法优化此阶段的性能

分代垃圾回收算法

  • 现代优秀的垃圾回收算法,会将上述描述的垃圾回收算法组合进行使用,其中应用最广的就是分代垃圾回收算法(Generational GC)。
  • 分代垃圾回收将整个内存区域划分为年轻代和老年代
    在这里插入图片描述

arthas查看分代内存情况

  1. 在JDK8中,添加-XX:+UseSerialGC参数使用分代回收的垃圾回收器,运行程序。
  2. 在arthas中使用memory命令查看内存,显示出三个区域的内存情况
    在这里插入图片描述

核心思想

  • 分代回收时,创建出来的对象,首先会被放入Eden伊甸园区。随着对象在Eden区越来越多,如果Eden区满,新创建的对象已经无法放入,就会触发年轻代的GC,称为Minor GC或者Young GC。Minor GC会把需要eden中和From需要回收的对象回收,把没有回收的对象放入To区。接下来,S0会变成To区,S1变成From区。当eden区满时再往里放入对象,依然会发生Minor GC。此时会回收eden区和S1(from)中的对象,并把eden和from区中剩余的对象放入S0。
  • 注意:每次Minor GC中都会为对象记录他的年龄,初始值为0,每次GC完加1。
    在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

  • 如果Minor GC后对象的年龄达到阈值(最大15,默认值和垃圾回收器有关),对象就会被晋升至老年代
    在这里插入图片描述
  • 当老年代中空间不足,无法放入新的对象时,先尝试minor gc如果还是不足,就会触发Full GC,Full GC会对整个堆进行垃圾回收。
    如果Full GC依然无法回收掉老年代的对象,那么当对象继续放入老年代时,就会抛出Out Of Memory异常。
    在这里插入图片描述

虚拟机内存参数

  • 根据以下虚拟机参数,调整堆的大小并观察结果。注意加上-XX:+UseSerialGC
参数名参数含义示例
-Xms设置堆的最小和初始大小,必须是1024倍数且大于1MB比如初始大小6MB的写法: -Xms6291456、-Xms6144k、-Xms6m
-Xmx设置最大堆的大小,必须是1024倍数且大于2MB比如最大堆80 MB的写法:-Xmx83886080、-Xmx81920k、-Xmx80m
-Xmn新生代的大小新生代256 MB的写法:-Xmn256m、-Xmn262144k、-Xmn268435456
-XX:SurvivorRatio伊甸园区和幸存区的比例,默认为8新生代1g内存,伊甸园区800MB,S0和S1各100MB比例调整为4的写法:-XX:SurvivorRatio=4
-XX:+PrintGCDetails/verbose:gc打印GC日志

StopWorldTest案例代码

import lombok.SneakyThrows;
import java.util.LinkedList;
import java.util.List;

/**
 * STW测试
 */
public class StopWorldTest {
    public static void main(String[] args) {
        new PrintThread().start();
        new ObjectThread().start();
    }
}

class PrintThread extends Thread{

    @SneakyThrows
    @Override
    public void run() {
        //记录开始时间
        long last = System.currentTimeMillis();
        while(true){
            long now = System.currentTimeMillis();
            System.out.println(now - last);
            last = now;
            Thread.sleep(100);
        }
    }
}

class ObjectThread extends Thread{

    @SneakyThrows
    @Override
    public void run() {
        List<byte[]> bytes = new LinkedList<>();
        while(true){
            //最多存放8g,然后删除强引用,垃圾回收时释放8g
            if(bytes.size() >= 80){
                bytes.clear();
            }
            bytes.add(new byte[1024 * 1024 * 100]);
            Thread.sleep(10);
        }
    }
}

GC案例1

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * 垃圾回收器案例1
 */
//-XX:+UseSerialGC  -Xms60m -Xmn20m -Xmx60m -XX:SurvivorRatio=3  -XX:+PrintGCDetails
//-XX:+UseParNewGC -XX:+UseConcMarkSweepGC  -XX:ConcGCThreads
//-XX:+UseParallelGC  -XX:+UseParallelOldGC
public class GcDemo1 {

    public static void main(String[] args) throws IOException {
        List<Object> list = new ArrayList<>();
        int count = 0;
        while (true){
            System.in.read();
            System.out.println(++count);
            //每次添加1m的数据
            list.add(new byte[1024 * 1024 * 1]);
        }
    }
}

GC案例2

/**
 * 垃圾回收器案例2
 */
//-XX:+UseSerialGC -Xmn10m -Xmx30m -XX:SurvivorRatio=8  -XX:+PrintGCDetails -verbose:gc
public class GcDemo2 {

    public static void main(String[] args) throws IOException {
        List<Object> list = new ArrayList<>();
        int count = 0;
        while (true){
            System.in.read();
            System.out.println(++count);
            //每次添加1m的数据
            list.add(new byte[1024 * 1024 * 1]);
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/367528.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【android】对于google-webrtc的性能中, memory leak

目录 zlmediakit->webrtcplay->app webrtcutil1/3 测试程序等 zlmediakit->webrtcplay->app 编译sdk 32 有时候会从开始新增5M&#xff0c;就稳定在一个值了 webrtcutil1/3 测试程序等 编译sdk 30

关于可变类型和不可变类型的探究

个人猜想&#xff08;很遗憾失败了&#xff09; 在硬盘或者系统中存在一个字符集 如果存在硬盘中&#xff0c;那么硬盘出厂的时候他的字符集所占用的空间就已经确定了。 如果存在于系统的话&#xff0c;硬盘应该在出厂的时候为系统设置一个存储系统字符集的地方。在安装系统…

【Chrono Engine学习总结】2-可视化

由于Chrono的官方教程在一些细节方面解释的并不清楚&#xff0c;自己做了一些尝试&#xff0c;做学习总结。 0、基本概念 类型说明&#xff1a; Chrono的可视化包括两块&#xff1a;实时可视化&#xff0c;以及离线/后处理可视化。 其中&#xff0c;实时可视化&#xff0c;又…

蓝桥杯省赛无忧 背包问题 课件 课件61 多重背包

01 多重背包基础模型 02 小明的背包3 03 二进制优化模型 04 新一的宝藏搜寻加强版

Linux Rootkit实验|0201 基本功能之Root后门

Linux Rootkit实验&#xff5c;0201 基本功能之Root后门 11 May 2017 文章目录 Linux Rootkit实验&#xff5c;0201 基本功能之Root后门实验说明实验环境实验过程提供 root 后门 实验总结与思考参考资料参考资料 时人不识凌云木&#xff0c;直待凌云始道高。 实验说明 本次实…

压力测试工具-Jmeter使用总结

目录 一.前言 二.线程组 三.线程组的组件 四.线程组-HTTP请求 1、JSON提取器 2、XPATH提取器 3、正则表达式提取器 五.线程组-断言 1、响应断言 2、JSON断言 六.创建测试 1.创建线程组 2.配置元件 3.构造HTTP请求 4.添加HTTP请求头 5.添加断言 6.添加查看结果树…

SAFe大规模敏捷认证Leading SAFe官方认证班

课程简介 SAFe – Scaled Agile Framework是目前全球运用最广泛的大规模敏捷框架&#xff0c;也是全球敏捷相关认证成长最快、最被认可、最有价值的规模化敏捷认证&#xff0c;目前全球SAFe认证专业人士已达120万人。 据官方统计&#xff0c;获得新证书的IT专业人士的平均工资…

寒假作业2月2号

第一章 命名空间 一&#xff0e;选择题 1、编写C程序一般需经过的几个步骤依次是&#xff08;C &#xff09; A. 编辑、调试、编译、连接 B. 编辑、编译、连接、运行 C. 编译、调试、编辑、连接 D. 编译、编辑、连接、运行 2、所谓数据封装就是将一组数据和与这组数据有关…

Pycharm python用matplotlib 3D绘图显示空白解决办法

问题原因&#xff1a; matplotlib版本升级之后显示代码变了&#xff0c;修改为新的 # ax Axes3D(fig) # 原代码 ax fig.add_axes(Axes3D(fig)) # 新代码import numpy as np import matplotlib.pyplot as plt from matplotlib import cm from mpl_toolkits.mplot3d import Ax…

Electron开发的十大神级产品,vscode、atom、skype、figma等

Hi、我是贝格前端工场&#xff0c;今天分享一下基于Electron的十大著名产品&#xff0c;欢迎友友们补充。 Visual Studio Code 这是一款由微软开发的轻量级代码编辑器&#xff0c;它提供了丰富的功能和插件生态系统&#xff0c;支持多种编程语言和开发工具。Visual Studio Cod…

PDF中公式转word

效果&#xff1a;实现pdf中公式免编辑 step1: 截图CtrlAltA&#xff0c;复制 step2: SimpleTex - Snip & Get 网页或客户端均可&#xff0c;无次数限制&#xff0c;效果还不错。还支持手写、文字识别 单张图片&#xff1a;选 手写板 step3: 导出结果选择 注&#xff1a;…

【笔记】Android 常用编译模块和输出产物路径

模块&产物路径 具体编译到软件的路径要看编译规则的分区&#xff0c;代码中模块编译输出的产物基本对应。 Android 代码模块 编译产物路径设备adb路径Comment 模块device/mediatek/system/common/ 资源overlay/telephony/frameworks/base/core 文件举例res/res/values-m…

开源的三维算法库有哪些

PCL,VTK,VCG,CGAL&#xff0c;Open CASCADE&#xff08;opencascade&#xff09;&#xff0c;OpenSceneGraph (OSG)&#xff0c; 点云网格处理算法&#xff1a;openmesh, meshlab三维算法库&#xff0c;Eigen 网格简化&#xff0c;网格平滑&#xff0c;网格参数化 无序点云网…

[Linux 进程(六)] 写时拷贝 - 进程终止

文章目录 1、写时拷贝2、进程终止2.1 进程退出场景2.1.1 退出码2.1.2 错误码错误码 vs 退出码2.1.3 代码异常终止引入 2.2 进程常见退出方法2.2.1 exit函数2.2.2 _exit函数 本片我们主要来讲进程控制&#xff0c;讲之前我们先把写时拷贝理清&#xff0c;然后再开始讲进程控制。…

与指定数字相同的数的个数 T1061

#include<bits/stdc.h> using namespace std; int n,m; const int N110; int f[N]; int a0; int main(){cin>>n>>m;for(int i0;i<n;i)cin>>f[i];for(int j0;j<n;j){if(f[j]m){a;}}cout<<a<<endl;return 0; }

安科瑞消防设备电源监控系统在地铁工程的设计与应用

【摘要】&#xff1a;本文介绍了地铁工程中消防设备电源监控系统设置的必要性及规范求&#xff0c;分析了监控设计方案&#xff0c;提出该系统在地铁工程中的应用要求及建议&#xff0c;以供地铁工程建设参考。消防设备电源监控系统主要针对消防用电设备的电源进行实时的监控&a…

react 之 zustand

zustand可以说是redux的平替 官网地址&#xff1a;https://zustand-demo.pmnd.rs/ 1.安装 npm i zustand2.基础使用 // zustand import { create } from zustand// 1. 创建store // 语法容易出错 // 1. 函数参数必须返回一个对象 对象内部编写状态数据和方法 // 2. set是用来…

Springboot做查询数据库某个表的数据时,后台一切正常前台显示不了数据

当我在用springboot做项目的时候查询整个表的数据或者条件查询的时候发现我的后台功能一切正常但是我的前台界面就是显示不了数据&#xff0c;这个问题解决也很简单&#xff0c;就是需要我们平时多加注意&#xff0c;不要漏代码&#xff01;&#xff01;&#xff01; Builder …

51单片机学习笔记 --步进电机驱动说明

文章目录 工作原理代码编写驱动方式全步进驱动半步进驱动微步进驱动 工作原理 工作原理简要说明&#xff0c;和单片机一起配合使用的步进电机多为28BYJ28 五线四相步进电机&#xff0c;配合ULN2003驱动板进行控制&#xff0c;如图所示&#xff0c;对于扭矩、精度要求较高的还有…

【开源】JAVA+Vue.js实现校园二手交易系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 二手商品档案管理模块2.3 商品预约管理模块2.4 商品预定管理模块2.5 商品留言板管理模块2.6 商品资讯管理模块 三、实体类设计3.1 用户表3.2 二手商品表3.3 商品预约表3.4 商品预定表3.5 留言表3.6 资讯…