JVM-垃圾回收-基础知识

news2024/11/16 15:52:03

基础知识

什么是垃圾

简单说就是没有被任何引用指向的对象就是垃圾。后面会有详细说明。

和C++的区别

java:GC处理垃圾,开发效率高,执行效率低

C++:手工处理垃圾,如果忘记回收,会导致内存泄漏问题。如果回收多次,则会导致非法访问问题。开发效率低,执行效率高

如何定位垃圾

引用计数法

英文:reference count,当有引用指向对象时,给引用的数量计数,当引用数量等于0时,对象就被判定为垃圾。

这种方法无法解决的问题:循环引用。例如:A > B > C > A,彼此互相引用,引用计数都是1,但其实没有任何其他引用指向他们。使用引用计数法,这些对象将永远无法垃圾回收。所以需要其他算法。Python用的是这种算法。

根可达算法

英文:Root Searching,这是JVM实际使用的算法。首先定义好一系列的根对象(GC Root),如果一个对象向上追溯没有被GC Root引用就是垃圾。那么GC Root有哪些?

线程栈变量

从main方法开始,会启动一个主线程,然后会有一个main的栈帧,这里面中的对象就是线程栈变量。

静态变量

静态变量一个类只有一个,当类初始化时,马上就会引用到静态变量,所以静态变量也是Root对象。被静态变量引用的对象不能被回收。

常量池

Runtime constant pool,常量池中引用指向的对象,类似静态变量。

JNI指针

本地方法(native)用到的类或者对象。

垃圾回收算法

标记清除(mark sweep)

第一遍:扫描整个堆,标记出可回收的垃圾。

第二遍:扫描整个堆,将刚刚标记出来的垃圾清除。

缺点:

对象清除以后内存不连续会产生空间碎片

标记和清除比较耗时,效率比较低。
在这里插入图片描述

拷贝算法 (copying)

也叫复制算法,将内存划分为两块相等的区域,每次只使用其中一块,当其中一块内存使用完了,就将还存活的对象复制到另外一块上面,然后把已经使用过的内存空间一次清除掉。

缺点:空间浪费,复制操作会增加额外开销。

优点:空间连续,没有碎片

适用场景:少量对象存活的场景

在这里插入图片描述

标记压缩(mark compact)

复制算法在 GC 之后存活对象较少的情况下效率比较高,但如果存活对象比较多时,会执行较多的复制操作,效率就会下降。而老年代的对象在 GC 之后的存活率就比较高,所以就有人提出了“标记-整理算法”。

标记过程与"标记-清除"算法类似,但是后续步骤不是直接对可回收对象进行清理,而是将所有存活的对象都向一端移动,然后清理掉端边界以外的内存。

没有碎片,效率偏低(两遍扫描,指针需要调整)
在这里插入图片描述

内存分代模型

内存分代模型也有另一个名字:分代收集算法。这种算法整合了以上所有算法的优点,最大程度避免了它们的缺点。

与其说它是算法,倒不是说它是一种策略,因为它是把上述几种算法整合在了一起。

内存分代模型是部分垃圾回收器使用的模型,也有新的垃圾回收器是不分代的。例如:Epsilon,ZGC,Shenandoah。G1 是逻辑分代,物理不分代。

根据实际场景,其实大部分的对象都很短命,一般来说,98% 的对象都是朝生夕死的,所以分代收集算法根据对象存活周期的不同将堆分成新生代和老年代。

如下图:新生代和老年代的默认比例为 1 : 2,新生代又分为 Eden 区, from Survivor 区(简称 S0 ),to Survivor 区(简称 S1 ),三者的比例为 8: 1 : 1。

在这里插入图片描述

一个对象从出生到死亡的过程

在这里插入图片描述

对象分配过程
在这里插入图片描述1. 刚刚诞生的新对象首先会尝试在栈上分配。什么样的对象会分配到栈上?

  1. 线程私有小对象。

  2. 无逃逸。(就在某1个方法中使用的对象,没有其他地方引用)

  3. 支持标量替换(例如:某些对象就2个int属性,那就可以用2个int来代替整个对象)

  4. (一般无需调整)

  5. 如果在栈上分配不下且这个对象又很大,则会直接进入老年代。

    1. 多大算大,是由一个参数控制的。
  6. 如果栈分配不下且对象不够大,默认优先放到eden区的TLAB(Thread Local Allocation Buffer)

    1. 每个线程独有区域,默认占用eden的1%
    2. 避免多线程的时候eden空间的竞争,提高效率
    3. 小对象(证明TLAB的案例)
    4. 通过-XX:-UseTLAB可以关闭(一般无需调整)
  7. eden区的对象经过一次垃圾回收之后,能回收的直接回收了。不能回收的,会移动到S1区。

  8. 再回收1次就会连同eden区的某些存活对象一起进入S2区。再回收又会进入S1区,以此往复。每次回收都会让年龄+1。

  9. 当对象的年领大于设置的值时,对象就会进入到老年代。具体要符合下面条件的任意一个。

    1. 年龄大于XX:MaxTenuringThreshold中配置的值。不同的垃圾回收器,默认值不同。
      1. Parallel Scavenge:15
      2. CMS:6
      3. G1:15
      4. 由于JVM对象结构中GC年龄是4位,所以年龄最大就是15。
    2. 动态年龄
      1. 当S1把符合条件的对象拷贝到S2时(反过来也一样)
      2. 如果此时S2的空间占用超过50%,就会把年龄最大的对象放入老年代
    3. 分配担保
      1. YGC期间 survivor区空间不够了 空间担保直接进入老年代
      2. 参考:https://cloud.tencent.com/developer/article/1082730
  10. 老年代

    1. 顽固分子
    2. 老年代满了FGC Full GC

证明TLAB的案例

下面的代码,大家可以使用idea和jvm的默认参数执行一下,然后记录一下平均执行时间。

然后加上这些jvm参数后在执行一下:-XX:-DoEscapeAnalysis -XX:-EliminateAllocations -XX:-UseTLAB,应该会发现执行时间翻了接近一倍。

这些参数的含义。-XX:-DoEscapeAnalysis 关闭逃逸分析,-XX:-EliminateAllocations关闭标量替换,-XX:-UseTLAB关闭TLAB。关闭这些功能后会导致所有的对象都直接在eden区创建而不是栈中或者tlab,从而导致程序性能下降。

public class TestTLAB {
    class User {
        int id;
        String name;

        public User(int id, String name) {
            this.id = id;
            this.name = name;
        }
    }

    void alloc(int i) {
        new User(i, "name " + i);
    }

    public static void main(String[] args) {
        TestTLAB t = new TestTLAB();
        long start = System.currentTimeMillis();
        for (int i = 0; i < 1000_0000; i++) {
            t.alloc(i);
        }
        long end = System.currentTimeMillis();
        System.out.println(end - start);
    }
}

GC特点

当新生代空间不足时发生的 GC 称为 Young GC(YGC,也叫 Minor GC )

当老年代空间不足时发生的 GC 称为 MajorGC(也称为 Full GC )。此时新生代和老年代同时GC。

Minor GC 非常频繁,一般回收速度也比较快;出现了 Full GC,经常会伴随至少一次的 Minor GC,Full GC 的速度一般会比 Minor GC 慢10倍以上。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux Mint 21.2“Victoria”Beta 发布

导读近日消息&#xff0c;Beta 版 Linux Mint 21.2 “Victoria” 于今天发布&#xff0c;用户可以访问官网下载镜像。 Linux Mint 21.2 代号 “Victoria” &#xff0c;基于 Canonical 长期支持的 Ubuntu 22.04 LTS&#xff08;Jammy Jellyfish&#xff09;操作系统&#xff0…

2023年第三届工业自动化、机器人与控制工程国际会议

会议简介 Brief Introduction 2023年第三届工业自动化、机器人与控制工程国际会议&#xff08;IARCE 2023&#xff09; 会议时间&#xff1a;2023年10月27 -30日 召开地点&#xff1a;中国成都 大会官网&#xff1a;www.iarce.org 2023年第三届工业自动化、机器人与控制工程国际…

JAVA http

javahttp 请求数据格式servletservlet生命周期servletrequest获取请求数据解决乱码response相应字符&字节数据 请求数据格式 servlet servlet生命周期 servlet request获取请求数据 解决乱码 response相应字符&字节数据 response.setHeader("content-type",…

A. Portal(dp优化枚举)

Problem - 1580A - Codeforces CQXYM发现了一个大小为nm的矩形。矩形由n行m列的方块组成&#xff0c;每个方块可以是黑曜石方块或空方块。CQXYM可以通过一次操作将黑曜石方块变为空方块&#xff0c;或将空方块变为黑曜石方块。 一个大小为ab的矩形M被称为传送门&#xff0c;当…

【Linux】程序员的基本素养学习

这是目录 写在前面一、内存管理1、分段2、分页 二、线程管理三、静态库1、编译1.1、预处理1.2、编译1.3、汇编1.4、链接2、编译器3、目标文件**.text****.data****.bss****__attribute__** 3.1、符号3.2、兼容C语言 -- extern C4、链接 -- ld 写在前面 本文记录自己的学习生涯…

五.组合数据类型

目录 1、数组类型 声明数组 初始化数组 数组赋值 访问数组元素 2、切片类型 1、定义切片 2、切片初始化 3、访问 4、空(nil)切片 5、切片的增删改查操作&#xff1a; 3、指针类型 1、什么是指针 2、如何使用指针、指针使用流程&#xff1a; 3、Go 空指针 4、指…

chatgpt赋能python:如何将Python打包-一个SEO优化指南

如何将Python打包 - 一个SEO优化指南 作为一名拥有10年Python编程经验的工程师&#xff0c;我意识到很多Python开发者面临一个共同的问题&#xff1a;如何将他们的Python项目打包并发布到PyPI上&#xff1f;打包一个Python项目不仅可以让您的代码更加组织化&#xff0c;也可以…

如何拆分PDF?拆分PDF软件分享!​

那么如何拆分PDF&#xff1f;PDF是一种流行的电子文档格式&#xff0c;它可以在不同的操作系统和设备上进行查看和共享&#xff0c;而不会因为不同的软件或硬件而出现兼容性问题。同时&#xff0c;在使用的过程中&#xff0c;PDF拆分PDF文件是一个比较常见的需求&#xff0c;它…

threejs入门

个人博客地址: https://cxx001.gitee.io 前言 随着HTML5的发布&#xff0c;我们可以通过WebGL在浏览器上直接使用显卡资源来创建高性能的二维和三维图形&#xff0c;但是直接使用WebGL编程来创建三维场景十分复杂而且还容易出问题。而使用Three.js库可以简化这个过程&#xff…

机器学习——决策树1(三种算法)

要开始了…内心还是有些复杂的 因为涉及到熵…单纯的熵&#xff0c;可以单纯 复杂的熵&#xff0c;如何能通俗理解呢… 我也没有底气&#xff0c;且写且思考吧 1. 决策树分类思想 首先&#xff0c;决策树的思想&#xff0c;有点儿像KNN里的KD树。 KNN里的KD树&#xff0c;是每…

如何将非平稳的时间序列变为平稳的时间序列?

可以采用现代信号处理算法&#xff0c;比如小波分解&#xff0c;经验模态分解&#xff0c;变分模态分解等算法。 以经济金融领域的数据为例&#xff0c;经济金融领域的数据作为一种时间序列&#xff0c;和我们平常工程领域分析的信号具有相同特性。一般来说&#xff0c;信号是…

在 Maya、ZBrush 和 Arnold 中重塑来自邪恶西部的 Edgar Gravenor

今天瑞云渲染小编给大家带来Giancarlo Penton 介绍的Edgar Gravenor项目背后过程&#xff0c;展示了皮肤纹理和头发是如何制作的&#xff0c;并解释了详细的服装是如何设置的。 介绍 大家好&#xff0c;我的名字是Giancarlo Penton。我是一名3D角色艺术家&#xff0c;最近毕业…

从零开始 Spring Boot 53:JPA 属性转换器

从零开始 Spring Boot 53&#xff1a;JPA 属性转换器 图源&#xff1a;简书 (jianshu.com) 这篇文章介绍如何在 JPA&#xff08;Hibernate&#xff09;中使用属性转换器。 在前篇文章中&#xff0c;我介绍了如何使用Embedded和Embeddable将一个类型嵌入实体类&#xff0c;并映…

初识mysql之表内容的增删查改

目录 一、插入 1. 插入基础语法 2. 单行数据 全列插入 3. 多行数据 全列插入 4. 插入&#xff0c;失败则更新 5. 替换 二、基础查询 1. 查询基础语法 2. 全列查询 3. 指定列查询 4. 表达式查询 5. 结果去重 6. where条件 6.1 比较运算符与逻辑运算符 6.2 查询…

爬虫入门指南(5): 分布式爬虫与并发控制 【提高爬取效率与请求合理性控制的实现方法】

文章目录 前言多线程与多进程多线程多进程多线程和多进程的选择 使用Scrapy框架实现分布式爬虫1. 创建Scrapy项目2. 配置Scrapy-Redis3. 创建爬虫4. 启动爬虫节点5. 添加任务到队列 并发控制与限制请求频率并发控制限制请求频率 未完待续... 前言 在进行爬虫任务时&#xff0c;…

STM32外设系列—红外遥控

文章目录 一、红外遥控简介二、红外遥控的原理三、二进制脉冲编码3.1 NEC码的位定义3.2 NEC遥控指令的数据格式 四、红外遥控程序设计思路五、红外遥控程序设计5.1 红外遥控初始化程序5.2 记录高电平持续时间函数5.3 中断服务函数5.4 读取键值5.5 参数定义 六、应用实例 一、红…

ADB原理,常用命令汇总及示例

一. ADB简介 ADB&#xff0c;即 Android Debug Bridge 是一种允许模拟器或已连接的 Android 设备进行通信的命令行工具&#xff0c;它可为各种设备操作提供便利&#xff0c;如安装和调试应用&#xff0c;并提供对 Unix shell&#xff08;可用来在模拟器或连接的设备上运行各种…

基于Java+SpringBoot+vue的食品安全管理系统设计与实现

博主介绍&#xff1a;✌擅长Java、微信小程序、Python、Android等&#xff0c;专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&#x1f3fb; 不然下次找不到哟 Java项目精品实战案…

基于Java+Vue前后端分离网络教学平台设计实现(源码+lw+部署文档+讲解等)

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

Ubuntu连不上网,在windows安装docker后

在windows上安装docker后&#xff0c;会依赖于virtualbox虚拟机&#xff0c;并且有虚拟网络&#xff0c;与ubuntu虚拟机网络产生冲突。 解决办法&#xff0c;打开网络适配器&#xff0c;禁用VirtualBox网络 这个时候就可以了。 ubuntu上使用docker pull镜像的时候&#xff0c…