JVM的垃圾回收

news2025/1/15 23:04:11

JVM简介

JVM 是 Java Virtual Machine 的简称,意为 Java虚拟机。
虚拟机:是指通过软件模拟的具有完整硬件功能、运行在一个完全隔离的环境中完整计算机系统

1.JVM的内存区域划分
jvm是一个java进程 每一个java进程就是一个jvm实例
一个进程运行过程中 就要从操作系统这里申请到一些内存资源 jvm也是如此 所以用一块内存供java代码执行时使用 jvm把这一块内存 有划分几个区域作为不同的用途
在这里插入图片描述
栈里面方法的调用关系 局部变量(使用的是递归调用)
栈空间和程序计数器 是每一个线程各有一份
每个线程 都是一个独立的执行逻辑 就能得到单独记录执行到哪里

下面有一段代码

class Test{
	public int n = 20;
	public static int a = 10;
}
public static void main(){
	Test t = new Test();
}

n是普通的成员变量 就是包含在new对象内部 堆上的
a是一个静态成员变量 是包含在类对象中方法区的
t是一个局部变量(引用类型) 栈上
这里栈上的t保存了堆上new Test()的内存地址

2.JVM类加载机制
把类从硬盘加载到内存中 java程序最开始就是写一个java文件编译成.class文件(字节码) 运行java程序JVM就会读取class文件 把文件内容 放到内存中并构成class对象

简单描述下类加载

  1. 加载找到class文件 打开文件 读取文件内容并尝试解析格式
    在java代码就是直接使用类
  2. 验证 检查当前.class文件格式 是否符合要求
    ,这一阶段的目的是确保Class文件的字节 流中包含的信息符合《Java虚拟机
    规范》的全部约束要求,保证这些信 息被当作代码运行后不会危害虚拟机自身的安全。
  3. 准备 给类对象分配内存
    最终目的是构造出完整的类对象 分配内存+初始化
    分配出来的内存空间 内容就是权威0的值(此时此刻 类对象上static成员也就是都是0)
  4. 解析 主要是初始化类对象中涉及到的一些字符串常量
  5. 初始化对类对象进行更具体的初始化操作初始化静态成员 执行静态代码块 加载父类

双亲委派模型(描述类加载过程中 如何找到.class文件)
JVM加载.class文件的时候需要用到"类加载器"模块
JVM中自带了三个类加载器
Bootstrap ClassLoader 负责加载标准库中的类
Extension ClassLoader 负责加载JVM扩展的库
Application ClassLoader 负责加载第三方库(mysql jdbc driver servlet jackson 等)

  1. 从Application ClassLoader开始
    不会立即就搜索第三方库的目录 而是先把加载任务委派给父亲 让父亲先尝试加载
  2. 到了Extension ClassLoader
    也不会立即搜索扩展库的目录 而是继续把任务派给父亲 让父亲先尝试加载
    3)再到Booststrap ClassLoader
    同样不会立即搜寻标准库 但是Bootstrap ClassLoadr没有父亲了就只能自己搜索 如果没找到这个类就会交给孩子完成 -> Extension ClassLoader
  3. 任务回到Extension ClassLoader
    如果找到了这个类 就进行后续加载
    如果没找到这个类就会交给孩子完成
    5)任务回到Application ClassLoader
    如果找到了类就进行后续加载
    如果没找到就会抛出一个异常

双亲委派模型 工作就是找.class文件 每个类加载器都有自己的"父亲"

一个类什么时候才会被加载?
类的加载使用的是懒汉模式 用到了才加载
分为以下三种情况

  1. 构造类的实例
  2. 使用了类的静态方法/静态属性
  3. 子类的加载会触发父类
    类加载之后 后续就不用加载了

类卸载 类的卸载
一般来说类卸载是属于特殊情况
类加载之后就不会考虑卸载 一直保持到程序运行结束
但有时我们服务器需要打 热补丁 需要卸载操作

3.JVM的垃圾回收机制(GC)
java的垃圾回收机制 会自动判定 某个内存是否会继续使用(如果不会 就会把内存当初垃圾 自动把垃圾释放掉)

垃圾回收 对于java来说 回收的是对象而不是字节(GC不是判定某个字节是不是垃圾而是判定对象是不是垃圾 进一步去进行回收的)

JVM中有几个内存区域 GC回收是回收的是那里的对象?
JVM的内存区域有栈 堆 方法区 栈空间不需要GC回收栈里面包含很多"栈帧"每一个栈帧对应一个方法 该方法执行结束 此时这个栈帧就销毁了 然后在栈上的局部变量就自然销毁了

程序计数器同理 线程销毁 也自然跟着销毁

方法区 类对象 很少会涉及对象的卸载

所以 堆 GC的主要战场

Java垃圾回收 分两步

  1. 判定对象是否是"垃圾"
    如果一个对象 在后续代码中不再被使用就可以看作是垃圾了 一个对象如果没有任何引用指用它就可以认为是垃圾(Java中要使用一个对象 只有一种途径 就是先创一个引用指向它 然后通过引用访问对象的属性/方法)
    例如:
public void test(){
	T t = new T();
	t.function();
}
test();

t是一个局部变量此时 test方法执行完毕之后 t 就自然销毁 此时 new T() 对象就没有引用了 此时 这个对象就是垃圾

判定对象是否是垃圾 就是看这个对象是否有引用指向它 那么如何看对象是否有引用指向它呢?

思路一: 引用计数
给这个对象里面安排一个计数器 每次有引用指向它 就把计数器加一 每次引用被销毁 计数器减一 当计数器为0 的时候就说明这个对象是垃圾了
例如:

class Test{
	int m;
	int n;
}
Test a = new Test();
Test b = a;
Test c = b;

对象中 会专门留一个空间来存储引用的个数
在这里插入图片描述

此处a这个引用指向Test
b指向引用a
c指向引用b
然后Test的就被引用了三次 所以计数器加三
在这里插入图片描述
然后我们将
a = null;
此时引用减少一次 计数器减一
在这里插入图片描述
当剩下两个引用都置为null时 这个对象就是垃圾了
在这里插入图片描述
这就是引用计数方案 但存在两个明显的缺陷

  1. 空间利用率比较低 浪费更多的内存空间
    如果给引用计数分配了2各字节 对象本体才4各字节 引用计数就浪费了50%的空间 代码中都是小对象 并且数量多时浪费就很明显了
  2. 可能存在循环引用的问题 且对象不能被正确识别为垃圾
    例如:
class Test{
	public Test t;
}
//第一步
Test a = new Test();
Test b = new Test();
//第二步
a.t = b;
b.t = a;
//第三步
a = null;
b = null;

第一步时
在这里插入图片描述

第二步时
在这里插入图片描述
第三步时
在这里插入图片描述
此时这两个对象计算器不为0 不能被当作垃圾 于此同时 想要使用对象1 就要访问 对象2 想使用对象2就要访问道对象1 谁都用不了 谁有无法释放和死锁非常相似

方案二: 可达性分析 (这是java中实际采取的方式)
JVM 首先会从现有代码中能直接访问到的引用出发尝试遍历所有能访问的对象 只要对象能访问到就会标记成可达 完成所有遍历之后 不能访问到的对象就是不可达 就相当于垃圾了

gc root(从那些对象开始出发扫描?)

  1. 栈上的局部变量
  2. 常量池的引用
  3. 方法区中的静态成员

例如:

在这里插入图片描述
这样一颗二叉树结构
root = a
root.left = b
root.left.left = d
以此类推可以通过a进行访问到后续任何一个节点
如果此时令root.left.left = null 此时d就会空无法通过root遍历d就是不可达得了 此时d引用的对象就会被垃圾回收

以上就是可达性分析 和引用计数不同的时它消耗的是时间 通过引用计数可以非常快的知道对象是否是垃圾但是会消耗大量的空间
而可达性分析不会引入额外的空间开销 但进行遍历需要消耗时间

可达性分析的扫描是持续的 周期性的

  1. 释放对象的内存
    那我们确定了垃圾 又该如何清理垃圾 释放对象呢?

(1) 标记清除
直接释放对象 但是可能引起内存碎片
在这里插入图片描述
这是因为申请内存的时候都是申请连续的内存空间
释放内存就可能会破坏原有的连续性 导致内存申请不了 如果不处理内存碎片会随着程序的运行越来越多 越来越碎内存就会变得很难申请了

(2) 复制算法
复制算法 通过冗余的空间 把有效对象复制到另一个部分空间 避免内存碎片

把一个内存 分成两份用一份 删除一份
把左侧区域中有效的对象复制到右侧
使用右侧区域使用一段时间后存在很多对象然后把有效的对象在复制到左侧然后把左侧的对象全部同意释放
例如:
假设对象2是垃圾对象然后把13复制到右边内存再释放掉左侧内存

在这里插入图片描述
在这里插入图片描述
这里如果复制的内容多 内存开销很大内存率不高

(3) 标记整理
顺序表删除元素
假设34是

在这里插入图片描述
把5对象往前移两个单位内存就相当于删除了

在这里插入图片描述
这一方法解决了内存利用率低的问题但是
搬运的元素成本比较高

(4) 分代回收
Java代码中 对象分成两个大类
1.生命周期特别长
2.生命周期特别短
所以可以按照对象的年龄来定制不同的回收策略
GC就是周期性扫描 一个对象每经历一轮GC就看作长了一岁
在这里插入图片描述

新生的对象就在伊甸区 这里的对象大部分无法活过第一轮GC 第一轮gc经过之后还剩下的对象 就会被通过复制算法复制到幸存区

幸存区继续使用复制算法 如果这个对象在幸存区经过了许多轮依旧没有清理掉 就进入了老年代了

新生代的扫描频率比较高
老年代的扫描频率比较低

新生代每一轮gc留下的有效对象不过 使用复制算法开销不大
老年代不会有频繁的对象销毁对此 使用标记整理开销不大

还有一个特殊情况如果对象体积特别大就会直接进入老年代

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

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

相关文章

使用C++ __builtin_expect优化程序性能后,程序体积不改变原因

结论 使用__builtin_expect优化程序性能&#xff0c;开启-O3的情况下&#xff0c;确实程序的体积可能不改变&#xff0c;但是还是会产生优化效果。 测试代码 不使用__builtin_expect #include <iostream>void fun(int a, int b) {// 不使用__builtin_expectif (a <…

前端面试题 | 常考题整理

本文为面试中出现的高频次考题&#xff0c;具体还是要看所有题。 目录 css 1、☆介绍下 BFC 及其应用 3、☆浮动清除 17、☆说几个未知宽高元素水平垂直居中方法 js 9、☆箭头函数与普通函数的区别是什么&#xff1f;构造函数可以使用 new 生成实例&#xff0c;那么箭头…

Hass哈斯数控数据采集网络IP配置设置

机床数据采集&#xff08;MDC&#xff09;允许你使用Q和E命令通过网络接口或选项无线网络从控制系统提取数据。设置143支持该功能&#xff0c;并且指定控制器使用这个数据端口。MDC是一个需要一台附加计算机发送请求&#xff0c;解释说明和存储机床数据的软件功能。这个远程计算…

【Vue】结合ElementUI实现简单数据请求和页面跳转功能

一、准备工作 1、创建一个Vue-cli程序 之前的博客有。各位看官姥爷&#xff0c;可以自查。 2、安装ElementUI 在创建Vue-cli程序的过程中&#xff0c;需要在控制台执行以下指令&#xff1a; #安装 element-ui npm i element-ui -S #安装 SASS 加载器 cnpm install sass-loa…

SD卡和TF卡

SD卡和TF的电信号区别在于 SD比TF多一个地线。 请注意假如TVS结电容过高会导致无法通信&#xff0c;对于高速的通信同样如此&#xff0c;需要控制好ESD的结电容。 SD卡线需要注意50ohm阻抗要求 https://blog.csdn.net/jiangfutao/article/details/124466153 SD卡&#xff1a; …

解析ProxySQL的故障转移机制

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 解析ProxySQL的故障转移机制 前言故障检测故障切换策略故障转移流程 前言 在数据库的世界里&#xff0c;故障就像是一颗定时炸弹&#xff0c;随时可能引发系统崩溃。而ProxySQL&#xff0c;就像是这场…

组织机构树形列表实现

先看下效果图&#xff1a; 主要是用xm-select.js组件做的一个树形列表 xm-select.js的说明文档&#xff1a;https://maplemei.gitee.io/xm-select/?select1#/basic/disabled 实现步骤&#xff1a; HTML部分 <!DOCTYPE html> <html lang"en"> <hea…

【Linux系统编程】第十五弹---调试器gdb使用

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】 目录 1、背景 2、安装gdb 3、gdb的使用 总结 1、背景 前面我们学习了文件编辑器&#xff0c;项目自动化构建工具&#xff0c;以及g…

mybatis-plus代码

项目结构 config package com.example.mpdemo.config;import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerIntercept…

1756jsp农产品销售管理系统Myeclipse开发mysql数据库C2C模式java编程计算机网页项目沙箱支付

一、源码特点 java 农产品销售管理系统 是一套完善的web设计系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统采用web模式&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发&#xff0…

Linux文本处理工具【tr、cut、sort、uniq】

1. tr 命令——替换、压缩、删除 tr (Text Replacer) 命令常用来对来自标准输入的字符进行替换、压缩和删除。 命令格式 &#xff1a;tr [选项]... SET1 [SET2] &#xff08;SET 是一组字符串&#xff0c;一般都可按照字面含义理解&#xff09; 选项&#xff1a; -d 删除 -s 压…

vue地址选择器-三级联选择器+详细地址

在页面的显示情况 前端拼接实现存储 具体实现步骤 1.安装中国全省市区的数据 在命令提示符窗口使用管理员身份进入对应vue项目的文件夹&#xff0c;在窗口安装 npm install element-china-area-data -S2.在script内引入安装的数据 import {regionData,codeToText } from…

SpringBoot 使用 @RequiredArgsConstructor(onConstructor_ = @Autowired) 报错解决

若使用 RequiredArgsConstructor(onConstructor_ Autowired) 启动报错&#xff0c;或者爆红可以使用以下方法解决 1. 安装或启用 Lombok插件 2. 检查 Lombok 版本 3. 若 onConstructor_ 爆红&#xff0c; 可能是IDEA中文软件包冲突 4. 若以上还是不行&#xff0c;可以添加…

CSS-盒子模型

盒子模型的重要组成部分 内容区域content&#xff1a;width , height 内边距&#xff1a;内边框和内容区域的距离Padding边框线&#xff1a;Border外边距&#xff1a;Margin Border (边框线) 属性&#xff1a;Border 属性值&#xff1a;边框线粗细px 线条样式 颜色(不区分…

工业无尘布的静电问题及解决方法

工业生产中&#xff0c;无尘布是一种常用的清洁工具&#xff0c;但在使用过程中&#xff0c;静电问题常常会给生产环境带来困扰。本文优斯特将探讨工业无尘布的静电问题&#xff0c;并介绍解决这些问题的方法。 1. 静电产生原因 工业无尘布在擦拭过程中可能会产生静电&#x…

使用凌鲨建立软件研发技能学习小组

凌鲨(OpenLinkSaas)的团队功能除了提供论坛功能&#xff0c;还能记录团队成员的成长记录。 使用方法 打开团队功能 团队功能在默认情况下是关闭的&#xff0c;你可以在登录后打开团队功能开关。 创建学习团队 日报/周报/个人目标一般是企业团队需要&#xff0c;建议关闭。 …

unity基础(一)

内容概要&#xff1a; 生命周期函数vector3 位置 方向 缩放旋转等信息Vector3欧拉角和Quaternion四元素unity脚本执行顺序设置 一 生命周期函数 方法说明Awake最早调用,所以一般可以再此实现单例模式OnEnable组件激活后调用,在Awake后会调用一次Start在Update之前调用一次&a…

Spring 中 @Transactional 是怎么引入事务 AOP 的?

在 Spring 中&#xff0c;Transactional 注解是管理事务的关键工具之一。它允许开发人员通过简单地在方法或类上添加注解来定义事务的边界&#xff0c;从而实现对数据库操作的事务管理。 Transactional 是基于 Spring AOP&#xff08;Aspect-Oriented Programming&#xff0c;…

【小笔记】问答系统可视化实现的三种方式

下面三种方式都是基于Python的哈&#xff0c;从简单到复杂。 方式一&#xff1a;命令行交互问答 优点&#xff1a;原始简单直接 方式二&#xff1a;使用Python可视化框架 优点&#xff1a;无需学习前端技术栈即可搭建一个web。 streamlit&#xff1a;⭐️⭐️⭐️⭐️gra…

炒美股怎么开户?

近年来&#xff0c;随着国内投资者对境外投资需求的不断增长&#xff0c;炒美股逐渐成为许多投资者的选择。然而&#xff0c;随着监管政策的不断完善&#xff0c;传统的互联网券商开户方式已经不再适用。那么&#xff0c;对于想要入场美股市场的投资者来说&#xff0c;该如何开…