当前位置: 首页 > news >正文

JVM—内存管理(运行时数据区)、垃圾回收

背景介绍

当JVM类加载器加载完字节码文件之后,会交给执行引擎执行,在执行的过程中会有一块JVM内存区域来存放程序运行过程中的数据,也就是我们图中放的运行时数据区,那这一块运行时数据区究竟帮我们做了哪些工作?我们常说的线上内存泄漏和内存溢出是因为什么?我们今儿来揭开看看它神秘的面纱。
摘自网上


过程

在讲述运行时数据区有哪些部分之前先讨论以下对象的创建流程

一、对象创建流程

在这里插入图片描述

在上一篇文章中已经讲述了类加载的过程,虚拟机需要给new的新对象分配内存空间,重点来说说它的下一步——分配内存

在分配内存的时候有两种方式:

1、指针碰撞

假设Java堆内存规整,所有的内存占用是连续空间,通过一个指针将已经使用和未使用的空间隔开,指针作为临界。

2、空闲列表

假设Java堆内存不规整,内存占用是零散的,此时JVM通过一个空闲列表(Free List)维护空闲内存信息,里面记录了哪些内存空间是可用的。再次分配新对象的时候直接从空闲列表中找哪块空间可以使用进行分配即可

但是在并发情况下可能会出现线程安全的问题,对象1和对象2同时拿到指针,对象1在分配完内存空间之后对象2也会分配内存空间,对象2就会把对象1的空间覆盖,导致数据被覆盖。那怎么解决这个问题呢?

两种方案解决线程不安全:

1、CAS:自旋锁不断重试

2、TLAB:在堆内存给每个线程预先分配一块内存,线程中每次要开辟空间就在预分配的内存中开辟



下面就进入我们的正题——内存管理
在这里插入图片描述

  • 线程共有:堆、方法区
  • 线程私有:程序计数器、Java虚拟机栈、本地方法栈


二、内存管理

1、 程序计数器(PC)

上官方百度百科介绍:
在这里插入图片描述
作用:存放当前线程执行的下一条指令地址。
在多线程环境下线程之间会涉及到线程切换问题,为了保证线程切换之后还能继续按照上一次切换的位置继续执行,PC会进行指令的记录。PC是线程独有的,不可共享



2、Java虚拟机栈

作用:

每个线程在创建时都会创建一个虚拟机栈,保存了一个一个的栈帧 。针对栈帧我们来具体说说,下图为Java虚拟机中栈帧的内部结构,每执行一个方法都会创建一个栈帧(一个方法对应一个栈帧) ,而栈帧中包含了四部分:局部变量表、操作数栈、方法返回地址、动态链接,而每一个栈帧执行的过程也是入栈、出栈的过程。
在这里插入图片描述

包括:

  • 操作数栈(Operand Stack):用来在执行字节码指令过程中用来计算的
  • 局部变量表(LocalVariables):在方法执行过程中实时记录每个局部变量对应的值
  • 方法返回地址(Return Address):地址
  • 动态链接(Dynamic Linking):符号引用转换为调用方法的直接引用

特点:

  • 线程私有
  • 遵守栈FIFO规则,方法开始执行栈帧入栈,方法执行完栈帧弹出,所以虚拟机不需要垃圾回收

存在的问题:

  • 如果线程太多了,但是没有足够空间创建虚拟机栈,会发生栈溢出
  • 方法调用层次太多,可能出现StackOverflowError


3、本地方法栈(Native Method Stacks)

作用:存储Native方法


4、方法区(Method Area)

作用:
存储被Java虚拟机加载过后的class类信息、常量、静态变量、编译后的代码
不知道大家是否还记得上一篇分享中讲到的类加载过程,其中加载这一步会通过类全限定名加载成class类对象,其中就会把class信息、静态变量、常量等信息加载到方法区,看下面这张图
在这里插入图片描述


5、堆(Heap)

在这里插入图片描述

所有线程共享的一块内存区域,在new对象的时候会在Heap分配内存空间。可以细分为:

  • 年轻代和老年代,对应的比例为2:1 ,新生代存放朝生夕死的对象,老年代存放生命周期较长的对象
  • 年轻代又可以分为Eden、From Survivor、ToSurvivor三个区,对应的比例为:8:1:1(默认情况下,可以通过-XX:SurvivorRatio来调整)

那三个区域中对象是如何进行流转的呢?我们具体来看一下

1、在最开始讲述对象创建流程中包含了一步是分配内存,就是通过指针碰撞或空间散列在Heap中分配内存,新new对象的对象JVM会默认优先分配在Eden区,当Eden区空间逐渐减少(可以默认配置Eden空间容量)的时候,就会触发Young GC来清理,Eden区对象就会放入Survivor区;
2、Survivor区每次分配内存只使用其中一块,Eden和Survivor存活对象会复制到另一块Survivor区中,Eden和原来的Survivor区对象会被清理掉。(这也是为什么图中我只在其中一个Survivor区画了对象,另一块Survivor区没画的原因
3、在对象头中记录了对象迭代的年龄(年龄计数器),当进入Survivor区开始每YoungGC一次年龄就会+1,当年龄达到15的时候就会进入老年代

从图上我们看到进入老年代的条件远不止年龄>=15这一个,对象会进入老年代的方式共有四个:

  1. 长期存活:对象头中记录了对象迭代的年龄,每次迭代都会—+1,当年龄达到15(默认)
  2. 超大对象:占用大量连续空间
  3. 动态年龄判断:servivor中相同年龄对象的总和>survivor空间一半
  4. 空间分配担保:Young GC后,新生代有大量对象对象存活,需要老年代分配担保

三、垃圾回收

在这里插入图片描述

垃圾回收是什么?

清理不再使用的对象,释放内存空间

为什么要进行垃圾回收?

如果不清理这些垃圾对象,那么它们会一直占用着内存,而不能给其他对象是用,最终垃圾对象越来越多,就会出现OOM

什么样的对象是垃圾?

JVM没有任何引用指向它的对象

如何判断对象是垃圾?

1、引用计数法

每个对象都保存一个引用计数器属性,用户记录对象被引用的次数,每被引用一次计数器值就+1;当引用失效时就-1。当计数器为0则表示是垃圾对象

2、可达性分析

从GC Roots开始,遍历,一层一层的往下级找引用对象,找到的对象就是存活对象,没找到的就是垃圾对象
在这里插入图片描述

垃圾回收的三种方式分别是哪些?

1、标记-清除算法(Mark-Sweep)

标记:标记出未引用对象
清除:回收所有被标记的未引用对象

问题:

  1. 如果堆内包含了大量的对象都是需要被回收,这时会执行大量标记和清除操作,导致执行效率降低
  2. 内存空间碎片化,标记和清除后会产生大量不连续的内存碎片,导致在之后在给对象分配内存空间的时候因为内存不足而再次触发Young GC

2、标记-复制算法(Mark-Copying)

基于标记-清除算法,解决碎片化问题。上文中我也提到了新生代中Survivor分为了From、To两个区域,每次只使用其中一块,当其中一块内存用完了,会将存活的对象复制到另一块区域上,然后清理掉使用的survivor区域,保证内存区域连续可用。

问题:
空间一分为2,利用率低,空间浪费

3、标记-整理(Mark-Compact)

基于标记-清除算法,解决内存碎片和空间浪费问题。将存活的对象向一端移动,清除标记的垃圾对象,保证区域连续可用
问题:
内存变动大,当对象位置移动相应的引用地址也会变动

如何选用使用什么回收算法呢?

分代回收:基于heap各个区域对象生命周期来看,每个区域采用不同的回收算法:

  • 新生代:标记-复制
  • 老年代:标记-清理/标记-整理

相关文章:

JVM—内存管理(运行时数据区)、垃圾回收

背景介绍 当JVM类加载器加载完字节码文件之后,会交给执行引擎执行,在执行的过程中会有一块JVM内存区域来存放程序运行过程中的数据,也就是我们图中放的运行时数据区,那这一块运行时数据区究竟帮我们做了哪些工作?我们…...

一百五十一、Kettle——Linux上安装的kettle8.2开启carte服务

一、目的 kettle8.2在Linux上安装好可以启动界面、并且可以连接MySQL、Hive、ClickHouse等数据库后,准备在Linux上启动kettle的carte服务 二、实施步骤 (一)carte服务文件路径 kettle的Linux运行的carte服务文件是carte.sh (二…...

19. python从入门到精通——Web编程

HTTP协议 HTTP协议的常用方法 方法 描述 GET 请求指定的页面信息,并返回实体主体。 POST 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或已有资源的修改。 …...

PostMan 教程

安装https://www.cnblogs.com/mafly/p/postman.html Postman 使用方法详解https://blog.csdn.net/fxbin123/article/details/80428216 postman进行http接口测试https://blog.csdn.net/five3/article/details/53021084 postman的使用方法详解!最全面的教程https:/…...

Http常见状态码

一、状态码大类 状态码分类说明1xx响应中——临时状态码,表示请求已经接受,告诉客户端应该继续请求或者如果它已经完成则忽略它2xx成功——表示请求已经被成功接收,处理已完成3xx重定向——重定向到其它地方:它让客户端再发起一个…...

C语言之位运算

一、什么是位运算 所谓位运算是指进行二进制位的运算 在系统软件中,常要处理二进位的问题 例如,将一个存储单元中的各二进位左移或右移一位,两个数按位相加等 二、位运算符和位运算 1、按位与 运算符(&) 参加运算的两个数据&#xff…...

c语言进阶部分详解(数据在内存中的存储)

大家好,今天要进行梳理的内容是数据在内存中的存储相关内容。 在C语言中,数据在内存中的存储是一个非常重要的概念。了解数据在内存中的存储方式可以帮助我们更好地理解程序的执行过程,优化内存使用,提高程序的性能。 目录 一.数…...

VIOOVI的ECRS工时分析软件分析:SOP的核心和特征是什么?

制定SOP的主要目的是为企业做技术储备、提供企业的工作效率、防止同样的错误反复出现、让员工作业有标准化的行为准则。以规定的成本、规定的工作时间,生产质量均匀、符合规范的产品。为了能够达到上述要求,如果制造现场的操作混乱,比如制作工…...

无涯教程-Perl - lock函数

描述 此函数将咨询锁放在共享变量或THING中包含的引用对象上,直到该锁超出范围。 lock()是一个"弱关键字":这意味着,如果您在调用该函数之前已通过该名称定义了该函数,则将改为调用该函数。 语法 以下是此函数的简单语法- lock THING返回值 此函数不返回任何值…...

SpringBoot案例-部门管理-前后端联调

前后端联调 教学资料中提供了“前端工程”,将其解压即可使用nginx,启动nginx后,访问:http://localhost:90 小结 开发流程 明确需求、阅读接口文档、思路分析、接口开发(遵循接口文档)接口调试 postman测…...

每天一道leetcode:139. 单词拆分(动态规划中等)

今日份题目: 给你一个字符串 s 和一个字符串列表 wordDict 作为字典。请你判断是否可以利用字典中出现的单词拼接出 s 。 注意:不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。 示例1 输入: s "leetcode", …...

【C++】友元(含内部类)

一、友元是什么 我把你添加为我的友元,那么你可以访问我的成员。特别注意:它是单向的。即,我把你添加为我的友元,我却不能访问你的成员,除非你把我添加为你的友元。 以下代码可以让你粗略了解友元的使用。 #includ…...

SQL | 检索数据

1-检索数据 1.1-检索单个列 SELECT prod_name FROM Products; 上述SELECT语句从Products表中检索一个名为prod_name的列。 所要查找的列在select后面,from关键字指出从那个表查询数据。 输出如下: prod_name8 inch teddy bear12 inch teddy bear18…...

typeScript 之 运算符

工具: PlayGround 算术运算符 运算符描述加-减*乘/除%取模(求余)自增–自减 注意和--,实例: let value 0; console.log(value); //0, 先显示再增加后为1 console.log(value); //2,先增加后为2再显示关系运算符 运算符描述 …...

BGP实验

题目 IP地址配置 172.16.X.0/24为模拟用户环回接口接口 172.16.7.X/32为BGP邻居关系建立的环回接口 R1: R2: R3: R4: R5: R6: R7: R8: BGP邻居关系建立、宣告和反射器、联邦配置 R…...

pytest fixture 常用参数

fixture 常用的参数 参数一:autouse,作用:自动运行,无需调用 举例一:我们在类中定义一个function 范围的fixture; 设置它自动执行autouseTrue,那么我们看下它执行结果 输出: 说明:…...

vue项目里面有多个模块的服务,前端处理url转发

先看下vue的代理配置里面: 现在是在 /pca 基础上增加了 2个模块的服务: /dca、 /api 现在服务器的nginx 没有在/pca 服务里面做转发接受 /dca、 /api的服务,所以需要前端自己去配置每个服务模块对应的 URL 先拿登录的api 做示例吧: 先定义…...

web表单

在了解了 Flask Bootstrap 基本框架之后,我们来了解一下 Flask 框架的 表单( form ),以帮助我们创建交互式的 Web 应用,最后会有个提交个人信息的例子。 Flask-WTF 是 Flask 框架的一个扩展,用来做表单的交互,是对 WT…...

C++BUG记录:文件无法创建,文件路径正确但使用了Format

问题1:xx.Format()不存在与参数列表匹配的重载函数 问题:文件的路径名字是通过Format转换组合而成的,会报错“FileName.Format()不存在与参数列表匹配的重载函数”。 FileName.Format("%s%d", FilePath, num);//报错:…...

nodejs框架 express koa介绍以及从零搭建 koa 模板

express 下载 npm install express搭建服务 const express require("express");const app express();app.get("/home", (req, res) > {res.send("home"); });app.listen(3000, () > {console.log("http://127.0.0.1:3000")…...

在软件开发中正确使用MySQL日期时间类型的深度解析

在日常软件开发场景中,时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志,到供应链系统的物流节点时间戳,时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库,其日期时间类型的…...

python/java环境配置

环境变量放一起 python: 1.首先下载Python Python下载地址:Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个,然后自定义,全选 可以把前4个选上 3.环境配置 1)搜高级系统设置 2…...

连锁超市冷库节能解决方案:如何实现超市降本增效

在连锁超市冷库运营中,高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术,实现年省电费15%-60%,且不改动原有装备、安装快捷、…...

在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module

1、为什么要修改 CONNECT 报文? 多租户隔离:自动为接入设备追加租户前缀,后端按 ClientID 拆分队列。零代码鉴权:将入站用户名替换为 OAuth Access-Token,后端 Broker 统一校验。灰度发布:根据 IP/地理位写…...

江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命

在华东塑料包装行业面临限塑令深度调整的背景下,江苏艾立泰以一场跨国资源接力的创新实践,重新定义了绿色供应链的边界。 跨国回收网络:废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点,将海外废弃包装箱通过标准…...

【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)

升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点,但无自动故障转移能力,Master宕机后需人工切换,期间消息可能无法读取。Slave仅存储数据,无法主动升级为Master响应请求&#xff…...

NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合

在汽车智能化的汹涌浪潮中,车辆不再仅仅是传统的交通工具,而是逐步演变为高度智能的移动终端。这一转变的核心支撑,来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒(T-Box)方案:NXP S32K146 与…...

MySQL 知识小结(一)

一、my.cnf配置详解 我们知道安装MySQL有两种方式来安装咱们的MySQL数据库,分别是二进制安装编译数据库或者使用三方yum来进行安装,第三方yum的安装相对于二进制压缩包的安装更快捷,但是文件存放起来数据比较冗余,用二进制能够更好管理咱们M…...

NPOI操作EXCEL文件 ——CAD C# 二次开发

缺点:dll.版本容易加载错误。CAD加载插件时,没有加载所有类库。插件运行过程中用到某个类库,会从CAD的安装目录找,找不到就报错了。 【方案2】让CAD在加载过程中把类库加载到内存 【方案3】是发现缺少了哪个库,就用插件程序加载进…...

作为测试我们应该关注redis哪些方面

1、功能测试 数据结构操作:验证字符串、列表、哈希、集合和有序的基本操作是否正确 持久化:测试aof和aof持久化机制,确保数据在开启后正确恢复。 事务:检查事务的原子性和回滚机制。 发布订阅:确保消息正确传递。 2、性…...