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.rhkb.cn/news/330887.html

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

相关文章

amtlib.dll打不开怎么办?一键修复丢失amtlib.dll方法

电脑丢失amtlib.dll文件是什么情况&#xff1f;出现amtlib.dll打不开怎么办&#xff1f;这样的情况有什么解决方法呢&#xff1f;今天就和大家聊聊amtlib.dll文件同时教大家一键修复丢失amtlib.dll方法&#xff1f;一起来看看amtlib.dll文件丢失会有哪些方法修复&#xff1f; a…

Docker配置国内镜像源

添加Docker国内镜像源 在/etc/docker/daemon.json文件中添加以下内容&#xff1a; {"registry-mirrors": ["http://hub-mirror.c.163.com","https://docker.mirrors.ustc.edu.cn","https://registry.docker-cn.com"] }重启docker s…

【Python】—— lambda表达式

目录 &#xff08;一&#xff09;应用场景 &#xff08;二&#xff09;lambda 语法 &#xff08;三&#xff09;示例分析 &#xff08;四&#xff09;lambda参数形式 4.1 无参数 4.2 一个参数 4.3 默认参数 4.4 可变参数 &#xff1a;*args 4.5 可变参数 &#xff1a;…

第四十一天 | 62.不同路径 63.不同路径|| 343.整数拆分 96.不同的二叉搜索树

题目&#xff1a;62.不同路径 1.二维dp数组dp[i][j]含义&#xff1a;到达&#xff08;i&#xff0c;j&#xff09;位置有dp[i][j]种方法。 2.动态转移方程&#xff1a;dp[i][j] dp[i - 1][j] dp[i][j - 1] 3.初始化&#xff1a;dp[0][j] 1, dp[i][0] 1 &#xff08;第一…

Spring Cloud 之 Gateway

本篇主要介绍有关Gateway网关的相关内容。 目录 一、什么是网关 二、Gateway的使用 Gateway服务的搭建 Route Predicate Factories Gateway Filter Factories Filter GlobalFilter Filter的执行顺序 一、什么是网关 经常面试的人肯定知道&#xff0c;在去公司面试时…

CAN笔记第二篇,车载测试继续学起来!

在CAN协议中&#xff0c;“帧”是一个包含完整信息的独立单元&#xff0c;它具有特定的格式和结构&#xff0c;以确保数据在CAN总线上的可靠传输。这里的“帧”字可以理解为&#xff1a; 完整性&#xff1a;一个帧包含了所有必要的信息&#xff0c;从起始到结束&#xff0c;都遵…

【LeetCode】【1】两数之和(1141字)

文章目录 [toc]题目描述样例输入输出与解释样例1样例2样例3 提示进阶Python实现哈希表 个人主页&#xff1a;丷从心 系列专栏&#xff1a;LeetCode 刷题指南&#xff1a;LeetCode刷题指南 题目描述 给定一个整数数组nums和一个整数目标值target&#xff0c;请在该数组中找出…

视觉检测实战项目——九点标定

本文介绍九点标定方法 已知 9 个点的图像坐标和对应的机械坐标,直接计算转换矩阵,核心原理即最小二乘拟合 {𝑥′=𝑎𝑥+𝑏𝑦+𝑐𝑦′=𝑎′𝑥+𝑏′𝑦+𝑐′ [𝑥1𝑦11𝑥2𝑦21⋮⋮⋮𝑥9𝑦91][𝑎𝑎′𝑏𝑏′𝑐𝑐′]=[𝑥1′𝑦…

AI爆文写作:根据别人的爆款标题,如何通过名词替换改成自己的爆款标题?

在日常刷到爆文的时候&#xff0c;就可以培养自己的网感&#xff0c;为啥这篇文章会爆&#xff1f; 这篇爆文的标题有啥诀窍呢&#xff1f; 比如下面这一篇&#xff1a;《极简生活&#xff1a;变富就是每天循环5个动作》 我们可以发现&#xff0c;每天循环5个动作 这几个词语…

C#基础一

使用Visual Studio 2022&#xff08;VS2022&#xff09;编写C#控制台程序 1. 安装Visual Studio 2022 确保已安装Visual Studio 2022。如果未安装&#xff0c;请从Visual Studio官网下载并安装。 另一篇文章中已经有详细描述&#xff0c;这里就不在细说了。 VisualStudio2022…

【JavaEE 初阶(十)】JVM

❣博主主页: 33的博客❣ ▶️文章专栏分类:JavaEE◀️ &#x1f69a;我的代码仓库: 33的代码仓库&#x1f69a; &#x1faf5;&#x1faf5;&#x1faf5;关注我带你了解更多进阶知识 目录 1.前言2.JVM内存区域划分3.类加载3.1双亲委派模型 4.垃圾回收&#xff08;GC&#xff0…

1098: 堆的判断

解法&#xff1a; 堆是完全二叉树 用数组来存储 然后用定义判定 #include<iostream> #include<vector> using namespace std; int main() {int n;cin >> n;vector<int> vec(n);for (int i 0; i < n; i) cin >> vec[i];for (int i 0; i &…

LabVIEW超高温高压流变仪测试系统

LabVIEW超高温高压流变仪测试系统 超高温高压流变仪广泛应用于石油、天然气、化工等行业&#xff0c;用于测量材料在极端条件下的流变特性。随着计算机技术、测试技术和电子仪器技术的快速发展&#xff0c;传统的流变仪测试方式已无法满足现代工业的需求。因此&#xff0c;开发…

【全开源】沃德商协会管理系统源码(FastAdmin+ThinkPHP+Uniapp)

一款基于FastAdminThinkPHPUniapp开发的商协会系统&#xff0c;新一代数字化商协会运营管理系统&#xff0c;以“智慧化会员体系、智敏化内容运营、智能化活动构建”三大板块为基点&#xff0c;实施功能全场景覆盖&#xff0c;一站式解决商协会需求壁垒&#xff0c;有效快速建立…

就业班 第三阶段(CICD) 2401--5.15 day2 自动化构建打包、部署(Jenkins + maven+ gitlab+tomcat)

一、平滑发布与灰度发布 **什么叫平滑&#xff1a;**在发布的过程中不影响用户的使用&#xff0c;系统不会因发布而暂停对外服务&#xff0c;不会造成用户短暂性无法访问&#xff1b; **什么叫灰度&#xff1a;**发布后让部分用户使用新版本&#xff0c;其它用户使用旧版本&am…

vector的底层实现与模拟

嗨喽大家好&#xff0c;时隔许久阿鑫又给大家带来了新的博客&#xff0c;关于vector的模拟实现&#xff0c;下面让我们开始今天的学习吧&#xff01; vector的底层实现与模拟 1.关于vector中的插入和删除 2. vector中的拷贝构造和赋值 3.vector的构造函数 4.关于vector中浅…

微信小程序报错:notifyBLECharacteristicValueChange:fail:nodescriptor的解决办法

文章目录 一、发现问题二、分析问题二、解决问题 一、发现问题 微信小程序报错&#xff1a;notifyBLECharacteristicValueChange:fail:nodescriptor 二、分析问题 这个提示有点问题&#xff0c;应该是该Characteristic的Descriptor有问题&#xff0c;而不能说nodescriptor。 …

windows docker desktop 更换镜像存储目录

windows docker desktop 更换镜像存储目录 方法&#xff1a;如图&#xff0c;Browse浏览一个新的目录并选中&#xff0c;确定后&#xff0c;程序会开始stop&#xff0c;在stop完成前&#xff0c;会持续迁移原有镜像到新的位置&#xff0c;你会发现目标位置的磁盘占用空间越来越…

DNS服务的部署与配置(1)

一、DNS的定义 1、域名系统&#xff08;英文&#xff1a;Domain Name System&#xff0c;缩写&#xff1a;DNS&#xff09;是互联网的一项服务。 它作为将域名和IP地址相互映射的一个分布式数据库&#xff0c;能够使人更方便地访问互联网。 DNS使用UDP端口53。 当前&#xff0…

使用pygame绘制图形

参考链接&#xff1a;https://www.geeksforgeeks.org/pygame-tutorial/?reflbp 在窗口中绘制单个图形 import pygame from pygame.locals import * import sys pygame.init()window pygame.display.set_mode((600,600)) window.fill((255,255,255))# pygame.draw.rect(wind…