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各个区域对象生命周期来看,每个区域采用不同的回收算法:

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

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

阿里巴巴面试题---考察对底层源代码的熟悉程度

题目如图所示: 很多人可能会觉得两个输出都会是false,因为我们都会觉得""比较的是引用类型的地址,虽然放入的值都一样但是重新创造了新对象,地址不一样,所以结果都是false. 然而,当我们运行程序会发现结果都是false. 下面,我们来分析为什么是这样的结果. 我们知道…

DolphinScheduler集群搭建详细笔记

1.DolphinScheduler Cluster部署 1.1 集群部署规划 集群模式下,可配置多个Master及多个Worker。通常可配置2~3个Master,若干个Worker。由于集群资源有限,此处配置一个Master,三个Worker,集群规划如下。 主机名ip服务…

sklearn机器学习库(一)sklearn中的决策树

sklearn机器学习库(一)sklearn中的决策树 sklearn中决策树的类都在”tree“这个模块之下。 tree.DecisionTreeClassifier分类树tree.DecisionTreeRegressor回归树tree.export_graphviz将生成的决策树导出为DOT格式,画图专用tree.export_text以文字形式输出树tree.…

【论文阅读】DEPCOMM:用于攻击调查的系统审核日志的图摘要(SP-2022)

Xu Z, Fang P, Liu C, et al. Depcomm: Graph summarization on system audit logs for attack investigation[C]//2022 IEEE Symposium on Security and Privacy (SP). IEEE, 2022: 540-557. 1 摘要 ​ 提出了 DEPCOMM,这是一种图摘要方法,通过将大图划…

axios请求

参考:https://www.axios-http.cn/docs/instance

windows安装docker 异常解决

Docker for Windows 安装Docker for Windows报错信息:Docker Desktop requires Windows 10 Pro/Enterprise/Home (18363). 解决方式 1.更新 Windows 系统版本Windows10Upgrade9252.exe 下载地址下载完运行 Windows10Upgrade9252.exe更新完,安装 Docke…

【Hilog】鸿蒙系统日志源码分析

【Hilog】鸿蒙系统日志源码分析 Hilog采用C/S结构,Hilogd作为服务端提供日志功能。Client端通过API调用(最终通过socket通讯)与HiLogd打交道。简易Block图如下。 这里主要分析一下。Hilog的读、写、压缩落盘,以及higlog与android…

python异步IO完全指南

原地址:https://flyingbyte.cc/post/async_io/ python异步IO完全指南 做为一种并行编程的範式,异步IO在Python中非常受重视,从Python3.4到3.7快速演进。 我们已经有多线程,多进程,并发(concurrency&#x…

第R3周 - 天气预测

🍨 本文为🔗365天深度学习训练营 中的学习记录博客🍖 原作者:K同学啊 我的环境: 语言环境:Python3.10.7编译器:VScode深度学习环境:TensorFlow 2.13.0 数据集: 一、前期…

健启星|医学营养的市场先行者

随着《“健康中国2030”规划纲要》、《国民营养计划(2017-2030年)》等政策的陆续发布,标志着以传统药物治疗为中心的医疗模式时代正式转型到以预防和康复为中心的新的医学营养时代。在此背景下,符合时代需求的特医食品成为“医学营…

UML箭头汇总

参考:http://www.cnblogs.com/damsoft/archive/2016/10/24/5993602.html 1.UML简介 Unified Modeling Language (UML)又称统一建模语言或标准建模语言。 简单说就是以图形方式表现模型,根据不同模型进行分类,在UML 2.0中有13种图&#xff…

Spring Boot | 使用mkcert本地生成SSL证书配置后端接口为HTTPS协议

Tips:本篇博客是 Windows 版本的使用教程,cmd 中执行的命令前缀是下载的软件名称,需要改成自己下载软件的名称! 下载软件 首先去 GitHub 仓库中下载软件,下载完成后将文件保存在英文路径下的文件夹,之后以…

Zookeeper 面试题

一、ZooKeeper 基础题 1.1、Zookeeper 的典型应用场景 Zookeeper 是一个典型的发布/订阅模式的分布式数据管理与协调框架,开发人员可以使用它来进行分布式数据的发布和订阅。 通过对 Zookeeper 中丰富的数据节点进行交叉使用,配合 Watcher 事件通知机…

搭建了个腾讯滑块服务,直接取ticket的,仅供测试.

最近闲着没事搭建了个TX滑块验证码服务,C#写的. 接口是rest接口 提交任务POST http://47.104.132.20:19090/task/addTask 提交数据: { "url": "https://ssl.captcha.qq.com/template/wireless_mqq_captcha.html?stylesimple&aid16&uin3557247785…

2023年中国负极石墨用坩埚市场规模现状及前景分析:负极材料为行业增长助推器[图]

负极石墨用坩埚分为再生坩埚和石墨匣钵,其中,再生坩埚主要应用于艾奇逊炉工艺的石墨化工序,石墨匣钵主要应用于预碳化和碳化工序。 负极石墨用坩埚分类 资料来源:共研产业咨询(共研网) 得益于动力电池的旺…

手机怎样换ip地址 更改手机IP地址有哪些方式

ip地址怎么改:使用深度ip转换器 在互联网时代,IP地址扮演着网络世界中的独特标识符。它是我们在上网时必不可少的元素,负责为设备提供独立的身份,并将信息传输到正确的目的地。然而,有时我们需要改变IP地址&#xff0c…

Kotlin 基础教程一

Kotlin 基本数据类型 Java | Kotlin byte Byte short Short int Int long Long float Float double Double boolean Boolean c…

基于身份的安全威胁正在迅速增长

根据端点安全和威胁情报供应商 CrowdStrike 发布的一份报告,目前最危险的网络安全威胁是能够访问给定系统合法身份信息的攻击者。 根据该报告,交互式入侵(该公司将其定义为攻击者积极工作以在受害者系统上实现某种非法目的的入侵)…

Java分布式微服务3——Docker

文章目录 Docker介绍安装DockerDocker基础操作Docker服务的启动镜像命令容器命令1. 从docker hub去查看Nginx容器的运行命令2. 查看所有容器状态3. 查看容器日志4. 进入Nginx容器执行命令,修改Html内容,添加“Hello World”5. 停止与开始容器6. 删除容器…

01 - 工作区、暂存区、版本库、远程仓库 - 以一次连贯的提交操作为例

1. 工作区、暂存区、版本库、远程仓库 以一次连贯的提交操作为例。 1.1 工作区 Git的工作区也就是我们平时编辑代码的目录文件夹。 新建一个kongfu_person.txt文件,工作区的变化: 1.2 工作区 > 暂存区:git add 1.3 暂存区 > 版本库…