JVM学习-堆空间(三)

JVM在进行GC时,并非每次都对新生代、老年代、方法区(元空间)三个区域一起回收,大部分时间回收的都是新生代
针对Hotspot VM的实现,它里面的GC按照回收区域分两大类型:一种是部分收集(Partial GC),一种是整堆收集(Full GC)

  • 部分收集:不是完整收集整个Java堆的垃圾收集
    • 新生代收集(Minor GC/Young GC)只回收新生代(Eden、S0,S1)
    • 老年代收集(Major GC/Old GC)只回收老年代
      • 目前只有CMS GC会有单独收集老年代的行为
      • 注:很多时候Major GC和Full GC混淆使用,需要具体分辨是老年代回收还是整堆回收
    • 混合收集:收集整个新生代和部分老年代的垃圾收集
      • 目前,只有G1 GC有这种行为
  • 整堆收集:收集整个java堆和方法区的垃圾收集
年轻代GC(Minor GC)触发机制
  • 当年轻代空间不足时,就会触发Minor GC,年轻代满指的是Eden区满,Survior满不会引发GC(每次Minor GC会清理年轻代的内存)
  • 因为Java对象大多具备朝生夕死的特性,所以Minor GC非常频繁,一般回收速度比较快
  • Minor GC会引发STW(Stop The World),暂停其它用户线程,等垃圾回收结束,用户线程才恢复执行
老年代GC(Major GC/Full GC)触发机制
  • 指发生在老年代的GC,对象从老年代消失时,Major GC或Full GC发生
  • 出现了Major GC,经常会伴随至少一次的Minor GC(非绝对,在Parallel Scavenge收集器的收集策略里就有直接进行Major GC的策略选择过程)
    • 老年代空间不足时,会先触发Minor GC,如果之后空间还不足,则触发Major GC
  • Major GC的速度一般比Minor GC慢10倍以上,STW的时间更长
  • 如果Major GC后,内存还不足,报OOM
Full GC触发机制
  • 调用System.gc()时,系统建议执行Full GC,不必须执行
  • 老年代空间不足
  • 方法区空间不足
  • 通过Minor GC后进入老年代的平均大小大于老年代的可用内存
  • 由Eden区、survivor space0(From space)区向survivor space1(To space)区复制时,对象大小大于To Space可用内存,则把该对象转存到老年代,且老年代的可用内存小于该对象大小
    注:Full GC是开发或调优中尽量避免的
/*** Administrator* 2024/5/18* 测试Minor GC,Major GC,Full GC* 执行参数 -Xms512m -Xmx512m -XX:+PrintGCDetails*/
public class GCTest {public static void main(String[] args) {int i = 0;try {List<String> list = new ArrayList<>();String str = "lotus.com";while (true) {list.add(str);str += str;i++;}} catch (Throwable t) {t.printStackTrace();System.out.println("遍历次数:" + i);}}
}//执行结果
[GC (Allocation Failure) [PSYoungGen: 117623K->20420K(153088K)] 117623K->74572K(502784K), 0.0395143 secs] [Times: user=0.03 sys=0.03, real=0.05 secs] 
[GC (Allocation Failure) [PSYoungGen: 133555K->1908K(153088K)] 408891K->314108K(502784K), 0.0160892 secs] [Times: user=0.08 sys=0.00, real=0.02 secs] 
[Full GC (Ergonomics) [PSYoungGen: 1908K->0K(153088K)] [ParOldGen: 312200K->221844K(349696K)] 314108K->221844K(502784K), [Metaspace: 3492K->3492K(1056768K)], 0.0218373 secs] [Times: user=0.16 sys=0.00, real=0.02 secs] 
[GC (Allocation Failure) [PSYoungGen: 0K->0K(153088K)] 221844K->221844K(502784K), 0.0010237 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Allocation Failure) [PSYoungGen: 0K->0K(153088K)] [ParOldGen: 221844K->221826K(349696K)] 221844K->221826K(502784K), [Metaspace: 3492K->3492K(1056768K)], 0.0046937 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
遍历次数:22
HeapPSYoungGen      total 153088K, used 6522K [0x00000000f5580000, 0x0000000100000000, 0x0000000100000000)eden space 131584K, 4% used [0x00000000f5580000,0x00000000f5bde8c0,0x00000000fd600000)from space 21504K, 0% used [0x00000000fd600000,0x00000000fd600000,0x00000000feb00000)to   space 21504K, 0% used [0x00000000feb00000,0x00000000feb00000,0x0000000100000000)ParOldGen       total 349696K, used 221826K [0x00000000e0000000, 0x00000000f5580000, 0x00000000f5580000)object space 349696K, 63% used [0x00000000e0000000,0x00000000ed8a08f0,0x00000000f5580000)Metaspace       used 3525K, capacity 4502K, committed 4864K, reserved 1056768Kclass space    used 391K, capacity 394K, committed 512K, reserved 1048576K
java.lang.OutOfMemoryError: Java heap spaceat java.util.Arrays.copyOf(Arrays.java:3332)at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:124)at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:448)at java.lang.StringBuilder.append(StringBuilder.java:136)at com.chapter06.GCTest.main(GCTest.java:19)
堆空间分代思想

经研究,不同对象的生命周期不同,70%-99%对象是临时对象

  • 新生代:有Eden、两块大小相同的Survivor(又称为from/to,s0/s1)构成,to总为空
  • 老年代:存放新生代中经历多次GC仍然存活的对象
    在这里插入图片描述
    在这里插入图片描述
为什么需要把Java堆分代?不分代不能正常工作吗?
  • 其实不分代完全可以,分代的唯一理由就是优化GC性能,如果没有分代,那所有的对象都在一块,就如同把学校的所有人关在一个教室,GC的时候要找到哪些对象没用,这样就会对全堆所有区域进行扫描,而很多对象朝生夕死,如果分代的话,新创建的对象放在某一地方,当GC的时候先把这块存储“朝生夕死”对象的区域进行回收,就会腾出很大空间
内存分配策略

如果对象在Eden出生并经过第一次MinorGC后仍然存活,并且能被Survior容纳的话,将被移动到Survivor空间中,并将对象年龄设置为1,对象在Survivor区中每熬过一次MinorGC,年龄就加1岁,当它的年龄增加到一定程度(默认15岁,其实每个JVM,每个GC都有所不同)时,会被晋升到老年代中

  • 对象晋升老年代的年龄阈值,可以通过选项 -XX:MaxTenuringThreshold来设置
    针对不同年龄对象分配原则如下:
  • 优先分配到Eden
  • 大对象直接分配到老年代
    • 尽量避免程序中出现过多大对象
  • 长期存活的对象分配到老年代
  • 动态对象年龄判断
    • 如果Survivor区中相同年龄的所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象可以直接进入老年代,无须等到MaxTenuringThreshold中要求的年龄
  • 空间分配担保
    • -XX:HandlePromotionFailure
//测试大对象直接进入老年代
/*** Administrator* 2024/5/18* -Xms60m -Xmx60m -XX:+PrintGCDetails -XX:NewRatio=2 -XX:SurvivorRatio=8*/
public class YoungOldAreaTest {public static void main(String[] args) {byte[] buffer = new byte[1024*1024*20];}
}
//执行结果
HeapPSYoungGen      total 18432K, used 2624K [0x00000000fec00000, 0x0000000100000000, 0x0000000100000000)eden space 16384K, 16% used [0x00000000fec00000,0x00000000fee90218,0x00000000ffc00000)from space 2048K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x0000000100000000)to   space 2048K, 0% used [0x00000000ffc00000,0x00000000ffc00000,0x00000000ffe00000)ParOldGen       total 40960K, used 20480K [0x00000000fc400000, 0x00000000fec00000, 0x00000000fec00000)object space 40960K, 50% used [0x00000000fc400000,0x00000000fd800010,0x00000000fec00000)Metaspace       used 3496K, capacity 4498K, committed 4864K, reserved 1056768Kclass space    used 387K, capacity 390K, committed 512K, reserved 1048576K
对象分配过程(TLAB)
  • 从内存模型而不是垃圾收集的角度,对Eden区域继续进行划分,JVM为每个线程分配了一个私有缓存区域,它包含在Eden空间内
  • 多线程同时分配内存时,使用TLAB可以避免一系列的非线程安全问题,同时还能够提升内存分配的吞吐量,因此我们可以将这种内存分配方式称为快速分配策略
  • 据我所知所有OpenJDK衍生出来的JVM都提供了TLAB的设计
为什么要有TLAB(Thread Local Allocation Buffer)
  • 堆区是线程共享区域,任何线程都可以访问到堆区中的共享数据
  • 由于对象实例的创建在JVM中非常频繁,因此在并发环境下从堆区划分内存空间是线程不安全的
  • 为避免多个线程操作同一地址,需要使用加锁等机制,进而影响分配速度
  • 尽管不是所有的对象实例都能够在TLAB中成功分配内存,但JVM确实是将TLAB作为内存分配的首选
  • 在程序中,开发人员可以通过选项“-XX:UseTLAB”设置是否开启TLAB空间
  • 默认情况下,TLAB空间内存非常小,仅占有整个Eden空间的1%,当然我们可以通过选项“-XX:TLABWasteTargetPercent”设置TLAB空间所占用Eden空间的百分比大小
  • 一旦对象在TLAB空间分配内存失败时,JVM就会尝试着通过使用加锁机制确保数据操作的原子性,从而直接在Eden空间中分配内存
    在这里插入图片描述
    在这里插入图片描述
堆空间参数
  • -XX:+PrintFlagsInitial:查看所有参数的默认初始值
  • -XX:+PrintFlagsFinal:查看所有的参数的最终值(可能存在修改,不再是初始值)
  • -Xms:初始堆空间大小(默认为物理内存的1/64)
  • -Xmx:最大堆空间大小(默认为物理内存的1/4)
  • -Xmn:设置新生代的大小(初始值及最大值)
  • -XX:NewRatio:配置新生代与老年代在堆结构的占比
  • -XX:SurvivorRatio:设置新生代中Eden和S0/S1空间的比例
  • -XX:MaxTenuringThreshold:设置新生代垃圾的最大年龄
  • -XX:+PrintGCDetails:输出详细的GC处理日志
    • 打印gc简要信息:-XX:+PrintGC | -verbose:gc
  • -XX:HandlePromotionFailure:是否设置空间分配担保

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

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

相关文章

Mysql之InnoDB索引

1.索引简介 官网介绍:MySQL :: MySQL 8.0 Reference Manual :: 10.3.1 How MySQL Uses Indexes 索引用于快速查找具有特定列值的行。如果没有索引&#xff0c; MySQL 必须从第一行开始&#xff0c;然后读取整个表以找到相关的行。表越大&#xff0c;花费就越多。如果表中有相关…

【C++算法】BFS解决单源最短路问题相关经典算法题

1.迷宫中离入口最近的出口 首先我们可以将这道题目简化一下&#xff0c;可以往我们这一章的主题上面来想想。 我们利层序遍历来解决最短路径问题&#xff0c;是最经典的做法。我们可以从起点开始层序遍历, 并组在遍历的过程中记录当前遍历的层数。这样就能在找到出口的时候&…

k8s遇到的错误记录

时隔四年有开始重新鼓捣k8s了&#xff0c;重新安装后遇到的错误记录如下&#xff1a; Error: Package: kubelet-1.14.0-0.x86_64 (kubernetes) Requires: kubernetes-cni 0.7.5 Available: kubernetes-cni-0.3.0.1-0.07a8a2.x86_64 (kubernetes) …

【zotero6】ZotCard笔记模板分享

zotcard插件下载链接&#xff1a;传送门 因为zotero出了新的zotero7&#xff0c;现在下载插件会出现zotero6和zotero7不兼容的情况&#xff0c;通过这个链接可以区分适配不同版本的插件。 下载后点击工具的附加组件 然后选择通过文件添加 就可以添加插件了 再通过 工具->…

F.费用报销【蓝桥杯】/01背包

费用报销 01背包 思路&#xff1a;f[i][j]表示前i个票据在容量为j的背包中能占的最大值。 #include<iostream> #include<algorithm> using namespace std; int day[13]{0,31,28,31,30,31,30,31,31,30,31,30,31}; int dp[1005][5005]; int s[13]; int last[1005];…

android实现PhotoShop里的魔棒效果

魔棒是画板工具一个重要的功能&#xff0c;非常实用&#xff0c;只要轻轻一点&#xff0c;就能把触摸到的颜色区域选中&#xff0c;做复制、剪切、擦除等工作。 那怎么实现呢&#xff1f; 先来看看效果&#xff1a; 要实现这个效果&#xff0c;需要对安卓canvas和paint理解比…

【html】网页布局模板01---简谱风

模板效果: 这是一种最简单,最干净的一种网页布局。 模板介绍: 模板概述: 这个模板是一个基础的网页布局模板,包括一个头部区域(header),其中包含网站标题(logo)和导航菜单(nav),以及一个页脚区域(copy),用于显示版权信息。整体布局简洁明了,适合作为各种类…

不靠后端,前端也能搞定接口!

嘿&#xff0c;前端开发达人们&#xff01;有个超酷的消息要告诉你们&#xff1a;MemFire Cloud来袭啦&#xff01;这个神奇的东东让你们不用依赖后端小伙伴们&#xff0c;也能妥妥地搞定 API 接口。是不是觉得有点不可思议&#xff1f;但是事实就是这样&#xff0c;让我们一起…

探索编程乐趣:绘制螺旋图的奇幻之旅

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、引言&#xff1a;编程的魔法世界 二、绘制螺旋图的准备工作 三、代码实战&#xff1a;…

X-SCAN:Rust从零实现一个命令行端口扫描工具

0. 成品预览 本文将基于Rust构建一个常见的网络工具&#xff0c;端口扫描器。 按照惯例&#xff0c;还是和之前实现的文本编辑器一样&#xff0c;我给这个工具起名为X-SCAN,它的功能很简单&#xff0c;通过命令行参数的方式对指定IP进行扫描&#xff0c;扫描结束之后返回该IP…

Spring AMQP 随笔 8 Retry MessageRecoverer ErrorHandler

0. 列位&#xff0c;响应式布局好麻烦的 … 有意思的&#xff0c;chrome devtool 在调试响应式的分辨率的时候&#xff0c;比如说在 宽度远远大于 768 的时候&#xff0c;按说浏览器也知道大概率是 web端方式打开&#xff0c;样式也是如此渲染&#xff0c;但一些事件(没有鼠标…

【IC设计】牛客网-序列检测习题总结

文章目录 状态机基础知识VL25 输入序列连续的序列检测VL26 含有无关项的序列检测VL27 不重叠序列检测VL28 输入序列不连续的序列检测参考资料 状态机基础知识 VL25 输入序列连续的序列检测 timescale 1ns/1ns module sequence_detect(input clk,input rst_n,input a,output re…

csdn的insCode怎么用IDE和linux终端

1.进入insCode&#xff0c;选择工作台 找到我的项目&#xff0c;没有项目的话可以新建一个。 选择在IDE中编辑&#xff0c;界面如下&#xff1a; 右边有个终端&#xff0c;点击即可出现linux的xterm终端。

边用边充电影响寿命吗?看看计算机指令组成与操作类型

计算机指令集体系结构之指令 指令由操作码和地址码字段组成。 操作码指明了指令要完成的操作。 长度可以固定&#xff1a;比如RISC&#xff08;reduced instruction set computer&#xff09;精简指令集计算机 与之对应的RISC&#xff08;复杂指令集计算机&#xff09;&…

福昕PDF使用技巧

因为突然间学校的企业版WPS突然很多功能就不能使用了&#xff0c;所以转向福昕PDF。 一、合并文件 添加需要合并的文件&#xff0c;可以使用ctrla等方式全选 找到最上方的“合并文件” 二、文本注释

IDEA打开项目报错

IDEA打开项目报错&#xff1a; Cannot read scheme C:\Users\xxxxxx\AppData\Roaming\JetBrains\IntelliJIdea2023.2\qaplug_profiles\Default.xmljava.lang.AbstractMethodError: Receiver class com.soldevelo.qaplug.scanner.AnalysisProfileManager$2 does not define or i…

【讲解下PDM,PDM是什么?】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

【汽车之家注册/登录安全分析报告】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 1. 暴力破解密码&#xff0c;造成用户信息泄露 2. 短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉 3. 带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造…

借助Kong记录接口的请求和响应内容

和APISIX类似&#xff0c;Kong也是一个Api GateWay。 运行在调用Api之前&#xff0c;以插件的扩展方式为Api提供管理, 如 鉴权、限流、监控、健康检查等. Kong是基于Lua语言、Nginx以及OpenResty开发的&#xff0c;拥有动态路由、负载均衡、高可用、高性能、熔断&#xff08;基…

通过RAG架构LLM应用程序

在之前的博客文章中&#xff0c;我们已经描述了嵌入是如何工作的&#xff0c;以及RAG技术是什么。本节我们我们将使用 LangChain 库以及 RAG 和嵌入技术在 Python 中构建一个简单的 LLM 应用程序。 我们将使用 LangChain 库在 Python 中构建一个简单的 LLM 应用程序。LangChai…