JVM内存区域详解,一文弄懂JVM内存【内存分布、回收算法、垃圾回收器】

视频讲解地址

学习文档


一、内存区域

在这里插入图片描述


区域描述线程私有如何溢出
程序计数器为了线程切换后能恢复到正确的执行位置,每个线程都要有一个独立的程序计数器。唯一一个不会内存溢出的地方
虚拟机栈1. 每个方法执行的时候,Java虚拟机都会同步创建一个栈帧用于存储局部变量表、操作数栈、方法出口等信息。
2. 每一个方法从调用到执行完毕都对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
3. 局部变量表存储了编译期可知的各种Java基本数据类型和对象引用。
1. 线程请求的栈深度大于虚拟机所允许的深度时抛出 StackOverFlowError异常。
2. 栈扩容时无法申请到足够内存的时候抛出 OutOfMemoryError。
本地方法栈和虚拟机栈类似,本地方法栈是为本地(Native)方法服务的同【虚拟机栈】
方法区线程共享,用于存放被虚拟机加载后的类型信息、常量、静态变量、即时编译器编译后的代码缓存数据。
注:运行时常量池、元空间都属于方法区的一部分。
无法满足新的内存分配会抛出 OutOfMemoryError
堆(垃圾收集的主要区域)1. 基本上所有的对象都是在堆上分配的。
2. Java堆可以处于物理上不连续的内存空间中,但在逻辑上它应该被视为连续的。
无法满足新的内存分配会抛出 OutOfMemoryError
直接内存NIO通过使用Native函数库直接分配对外内存。不受Java堆大小限制,但是受机器的物理内存限制。无法满足新的内存分配会抛出 OutOfMemoryError

堆其实就是一大块内存区域,是用来存放对象的,对于一个应用来说最耗费内存的就是“对象”。因为在运行的过程中会创建无数个对象,所以内存回收(垃圾回收)的时候主要就是针对堆的垃圾进行回收。


常见的堆划分是:

  1. 把堆分为新生代和老年代
  2. 新生代分为一个Eden区和两个Survivor区,它们的内存占比是 8:1:1
  3. 注:但G1却不是这样的,它把堆分成数个大小相同的Regin块

二、回收时机


上面我们谈到内存空间,内存是有限的,想要健康持续的运行下去,就一定要回收“垃圾”。

那怎么判定一个对象是不是垃圾呢,就成了新的问题。

算法描述备注
引用计数算法当某个对象被引用的时候引用计数器就加一,引用失效时就减一,当没有引用的时候就说明可以被回收了。几乎没有使用它的,因为它无法解决循环依赖的问题。
可达性分析某些对象被定义为根(GC Roots),从GC Roots向下搜索的路径成为“引用链”,如果某个对象到GC Roots间没有任何引用,那说明它不可达,它就可以被回收了。目前都是用这种算法。

GC Roots并不是一个固定的对象,它是一组对象:

  1. 在虚拟机栈引用的对象,譬如各个线程被调用的方法堆栈中使用到的参数、局部变量、临时变量等。
  2. 在方法区中类静态属性引用的对象,譬如Java类的引用类型静态变量。
  3. 在方法区中常量引用的对象,譬如字符串常量池里的引用。
  4. 在本地方法栈中JNI(即 Native方法)引用的对象。
  5. Java虚拟机内部的引用,如基本数据类型对应的Class对象。
  6. 所有被同步锁(Sync)持有的对象。
  7. 除了这些固定的GC Roots,根据不同的垃圾回收器还可以有其他“临时性”地加入。

一个对象是否可以被回收,是要看有没有被GC Roots触达,而不是仅仅是 触达

在这里插入图片描述


不管是引用计数算法,还是可达性分析,都提到了引用。Java中的引用并不是简单的引用,它有四种不同的引用

引用类型描述
强引用被强引用的对象不会被回收。 new 的方式创建就是产生强引用。
软引用被软应用的对象,只有在内存不足的时候才会被回收。
弱引用被弱引用的对象,在下一次垃圾回收的时候就会被回收。
虚引用虚引用又被称为幽灵引用,它和回收没太大关系,只是在回收的时候,会收到一个系统的通知。

三、回收算法


已经知道了哪些对象是可以回收的,那就需要按照某种回收算法,去回收它们。
名称描述优缺点
标记-清除标记所有未被引用的对象,在GC的时候清空它们。优点:简单直观
缺点:会产生大量的内存碎片。如果下次需要分配一个大对象,没有连续空间的时候会提前触发GC。
标记-整理标记所有被引用的对象,将还存活的对象移动到一端,然后清除边界外的内存。优点:减少了内存碎片,相对于标记-清除减少了碎片化问题。
缺点:移动对象需要成本。
标记-复制将内存划分成两个相同大小的块,每次只使用其中一块。当一块的内存用完了,就将还存活的对象复制到另外一块,然后再把之前那块空间清空。

IBM公司有一项研究的结论是:新生代中98%的对象熬不过第一轮回收,所以不必按照 1:1 的比例来划分。
新生代分为三个区:一个Eden、两个Survivor,对象优先分配在Eden区,每次只使用Eden和一个Survivor,在垃圾回收的时候把还存活的对象移动到另外一个没有被使用的Survivor中。如果Survivor区空间不够,会把对象移动到老年代。


1. 两个Survivor,在有的地方被称为From和 To,或 S0、S1
2. 默认情况下Eden和两个Survivor的比例是 8:1:1
优点:减少了内存碎片,适用于对象生命周期短的场景。
缺点:空间浪费和复制成本。

四、回收器


回收算法是理论,回收器是实践,不同回收器都是基于理论进行真正的实践,在讨论回收器之前需要先了解下面几个点

  1. STW:Stop The World 的缩写,意味着在GC的时候,其它线程无法工作。
  2. 并行、并发:多个GC线程一起工作就是并行,GC线程和用户线程一起工作就是并发。
  3. 吞吐量:运行用户代码时间 / 运行用户代码时间+垃圾回收时间,通过算法可以得出想要提高吞吐量,就必须减少垃圾回收耗时。

下面是各个回收器的作用域,连线表示它们可以组合使用,红色线表示JDK9已经不推荐了。

在这里插入图片描述


名称描述效率STW回收算法作用域目标使用场景回收步骤
Serial它是单线程工作的,且在进行垃圾回收的时候,必须暂停所有的工作线程。串行标记-复制新生代快速的回收1. 在客户端模式下的默认新生代收集器。
2. 对于内存资源不多的情况下,它是所有收集器里额外内存消耗最小的。
在这里插入图片描述
Serial Old同上串行标记-整理老年代快速的回收同上同上
ParNew它支持多线程并行回收垃圾,其它与Serial收集器没什么大的差别。并行标记-复制新生代快速的回收是除了Serial之外唯一可以和CMS收集器配合工作的。在这里插入图片描述
Parallel Scavenge它和ParNew有很多相似的地方,不同的是它关注的是 达到一个可控制的吞吐量。并行标记-复制新生代提高吞吐量大规模的后台服务、批处理任务等,对吞吐量要求高的场景。同上
Parallel Old同上并行标记-整理老年代提高吞吐量同上同上
CMSCMS可以并发的去执行,并且可以部分STW的回收器。并发部分STW标记-清除老年代快速的回收对延迟敏感的应用,需要较短垃圾回收停顿时间。在这里插入图片描述
G11. G1将堆分成多个大小相同的Regin(大小在 1-32MB,默认是 2048个),每一个Regin都可以充当新生代或老年代中的某个区。
2. Regin中还有一个特殊的区域 Humongous Regin(大对象直接分在老年代,防止了反复拷贝移动) ,G1规定大小超过普通Regin一半的对象是大对象,大对象就存在Humongous Regin,它会独占一个、或多个连续Region。
3. 使用 Mixed GC 回收(下面讲)
并发部分STW标记-整理通吃满足高吞吐量的同时,尽可能地减少垃圾回收耗时大内存应用、需要可预测停顿时间的应用,JDK9开始成为默认的垃圾回收器。G1对于CMS并不是完全的碾压,G1的实现更加复杂,所以它所额外使用的内存和程序运行时的负载都比CMS高。

CMS和G1的对比

  1. CMS会产生内存碎片,且无法回收浮动垃圾(因为清理的时候是并发的,这时候工作线程可能产生新的垃圾)
  2. 关注点:CMS是快速的回收,G1是在限定的时间内(这个时间可以自定义),最大限度的回收(会把垃圾排序然后回收收益最大的部分)
  3. 作用范围:CMS是作用于老年代,G1是都可以
  4. 内存分布:G1对堆内存进行了大小相同的Regin划分,在Regin的基础上再进行新生代和老年代划分,CMS是传统的新生代、老年代分布
  5. 性能:CMS对CPU资源非常敏感可能会影响正常请求(因为回收的时候很多阶段是并发的),G1对内存要求较高(想想它对堆做了那么复杂的划分和逻辑,这些都是需要额外内存和cup支持的),所以更适合大堆
  6. G1的目的是代替CMS,JDK9之后默认的垃圾收集器就是G1,但CMS并不是一无是处,在内存小的时候还是更合适的

MinorGC、MajorGC、Full GC、Mixed GC

  1. MinorGC:是对新生代回收时候的GC,有时候也叫 youngGC
  2. MajorGC:是针对老年代的垃圾回收操作。出现 Major GC 通常会出现至少一次 Minor GC。有时候也叫 OldGC
  3. Full GC:Full GC 会清理整个堆和方法区,包括年轻代、老年代和方法区。FullGC对于方法区的回收主要是满足下面三个条件
    • Java堆中不存在该类的任何实例对象;
    • 加载该类的类加载器已经被回收;
    • 该类对应的java.lang.Class对象不在任何地方被引用,且无法在任何地方通过反射访问该类的方法。
  1. Mixed GC:它是G1才有的。不再是每次回收新生代、老年代了,而是把内存排序后,回收利益最大的,这也是G1这个名字的由来。

五、其它


注:G1并不是终点,后面还有ZGC它关注更低的延迟,但现在大家都还没用到,暂时先不去学习了


参考:

  1. 本文严重参考了《深入理解Java虚拟机》这本书
  2. https://tech.meituan.com/2016/09/23/g1.html

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

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

相关文章

获取当前设备的IP

背景: 在本地使用自带webUI的项目时,需要制定webUI的访问地址。 一般本地访问使用:127.0.0.1,配置为可以从其他设备访问时,需要指定当前设备的IP,或者指定为0.0.0.0。 例如:使用locust的时候&a…

【Python学习】Python学习18- 方法OS 文件/目录方法

目录 【Python学习】Python学习17- File方法 前言os.access()语法: os.chdir(path)语法 os.chflags(path, flags)语法 os.chmod(path, mode)os.chown(path, uid, gid)os.chroot(path)os.close(fd)os.unlink(path)os.popen(command[, mode[, bufsize]])os.read(fd, …

Python--循环语句

在 Python 中,循环语句用于重复执行一段代码多次。Python 主要提供了两种类型的循环:for 循环和 while 循环。 1. for 循环 for 循环用于遍历可迭代对象(如列表、元组、字典、字符串等)中的每个元素,并对每个元素执行…

精通业务:资深程序员的核心优势

在IT行业,我们常常听到关于技术实力、项目经验、团队协作等方面的讨论,但有一个重要因素常常被忽视,那就是对业务的了解。 对于资深程序员来说,懂业务和不懂业务之间的区别,犹如一道深邃的鸿沟,决定着他们…

MCS-51---串行通信的特点

目录 一.同步通信和异步通信 1.异步通信 2.同步通信 二.串行通信的方式 1.单工 2.半双工 3.全双工 三.串行通信的速率 四.MCS-51单片机结构 五.串行口的控制 1.串行口控制寄存器(SCON) 2.电源控制寄存器(PCON) 六.波特率的设计 七.串行口的工作方式 1.方式0 2.…

DM数据库安装注意事项

数据库安装注意事项 一、安装前 一些参数需要在数据库创建实例前找用户确认。 参数名参数掩码参数值备注数据页大小PAGE_SIZE32数据文件使用的页大小(缺省使用8K,建议默认:32),可以为 4K、8K、16K 或 32K 之一,选择的页大小越大…

k8s存储卷之动态

动态pv需要两个组件 1、卷插件,k8s本身支持的动态pv创建不包含NFS,需要声明和安装一个外部插件 Provisioner 存储分配器,动态创建pv,然后根据pvc的请求自动绑定和使用 2、StorageClass,用来定义pv的属性&#xff0c…

选择和训练模型(Machine Learning 研习之十一)

当您看到本文标题时,不禁感叹,总算是到了训练模型这一节了。 是啊,在之前的文章中,我们对数据进行了探索,以及对一个训练集和一个测试集进行了采样,也编写了一个预处理管道来自动清理,准备您的数…

大数据赋能电竞出海企业发展

近几年电竞行业发展迅速,我国单2022年新增近4万家电竞相关企业,竞争十分激烈。中国电竞市场规模在全球占比19%左右,海外有巨大的增量市场,特别是东南亚、中南亚和拉丁美洲是电竞市场增长最快的地区,在2020至2025年期间…

C#,求最长回文字符串的马拉车(Manacher)算法的源代码

一、回文字符串(Palindromic String) 回文字符串(Palindromic String)是指前、后向读起来完全相同的字符串。 回文字符串除了答题似乎没有什么用处 :P 二、求解思路 求解字符串的回文子串的基本思路: 1、遍历每个位…

HTML---CSS-引入样式表和选择器

CSS : Cascading Style Sheet 层叠式样式表 HTML 用于控制网页的结构&#xff0c;CSS则用于控制网页的外观&#xff0c;想要做出美观好看的网页&#xff0c;CSS是必须的 引入外部样式表&#xff1a; 它的属性 rel 和 type是固定的 语法&#xff1a; <link rel"styles…

16 SysTick—系统定时器

文章目录 16.0 前言16.1 SysTick 简介16.2 SysTick 寄存器介绍16.2.1 CTRL 控制及状态寄存器16.2.2 RELOAD 重载数值寄存器16.2.3 Current当前数值寄存器16.2.4 CALRB 校准值寄存器16.3 SysTick 定时实验16.3.1 编程要点16.3.2 代码分析16.3.2.1 SysTick 配置库函数16.3.2.2 配…

音频编辑软件:Studio One 6 中文

Studio One 6是一款功能强大的数字音乐制作软件&#xff0c;为用户提供一站式音乐制作解决方案。它具有直观的界面和强大的音频录制、编辑、混音和制作功能&#xff0c;支持虚拟乐器、效果器和第三方插件&#xff0c;可帮助用户实现高质量的音乐创作和制作。同时&#xff0c;St…

Java基础之虚拟机

1、前言 本篇基于网络整理&#xff0c;和自己编辑。在不断的完善补充哦。 2、什么是虚拟机&#xff1f; Java 虚拟机&#xff0c;是一个可以执行 Java 字节码的虚拟机进程。Java 源文件被编译成能被 Java 虚拟机执行的字节码文件( .class )。 Java 被设计成允许应用程序可以运…

格密码基础:SIS问题的定义与理解

目录 一. 介绍 二. SIS问题定义 2.1 直观理解 2.2 数学定义 2.3 基本性质 三. SIS与q-ary格 四. SIS问题的推广 五. Hermite标准型 六. 小结 一. 介绍 short interger solution problem短整数解问题&#xff0c;简称SIS问题。 1996年&#xff0c;Ajtai首次提出SIS问…

【数据结构】排序算法

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:数据结构 ⚙️操作环境:Visual Studio 2022 目录 &#x1f38f;排序的定义 &#x1f38f;排序的稳定性 &#x1f4cc;稳定性的定义 &#x1f4cc;稳定性的意义 &#x1f38f;内排序与外排序 &#x1f38f;八大内排…

GitHub图床搭建

1 准备Github账号 如果没有Github账号需要先在官网注册一个账号 2 创建仓库 在github上创建一个仓库&#xff0c;随便一个普通的仓库就行&#xff0c;选择公共仓库 3 github token获取 github token创建方式可以参考下面的方式&#xff1a; https://www.xichangyou.com/6…

c/c++中static的用法

概述 static&#xff1a; 作为c/c的关键字之一&#xff0c;具有多种含义和应用&#xff0c;static 关键字可用于声明变量、函数、类数据成员和类函数。默认情况下&#xff0c;在所有块的外部定义的对象或变量具有静态持续时间和外部链接。 静态持续时间意味着&#xff0c;在程…

MT1138-MT1150总结

1. 判断闰年方法 year%40&&year%400&#xff01;0||year%4000 #include<bits/stdc.h> using namespace std;int day(int year,int mouth){if(mouth1||mouth3||mouth5||mouth7||mouth8||mouth10||mouth12){return 31;}else if(mouth4||mouth6||mouth9||mouth11)…

python使用贪心算法求最大整数问题

对于使用贪心算法的一个比较经典的问题&#xff0c;主要是为了解决最大整数的拼接问题&#xff0c;如果给定一个列表&#xff0c;这个列表中所包括的是一些非负整数&#xff0c;如果对这些整数进行组合&#xff0c;怎样才能组合出一个最大的整数&#xff0c;这里要注意一个问题…