JVM学习-堆空间(三)

news2024/11/17 14:41:41

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
Heap
 PSYoungGen      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 1056768K
  class space    used 391K, capacity 394K, committed 512K, reserved 1048576K
java.lang.OutOfMemoryError: Java heap space
	at 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];
    }
}
//执行结果
Heap
 PSYoungGen      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 1056768K
  class 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.coloradmin.cn/o/1692857.html

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

相关文章

【新】snapd申请Let‘s Encrypt免费SSL证书、自动化续签证书

简介 之前写过一篇certbot申请SSL证书的文章&#xff1a;SSL证书申请&#xff0c;写得比较详细&#xff0c;但是最近发现使用snapd会更方便。 使用机器&#xff1a;Ubuntu 20.04 简单步骤 1、首先安装必要软件 sudo apt install snapd sudo apt install certbot sudo apt …

SQL语言实践

1.数据库 创建 CREATE DATABASE Database; 改名 ALERT DATABASE Data RENAME TO Database; 删除 DROP DATABASE Database; 2.表 创建&#xff1a; CREATE TABLE table(); 与主键&#xff0c;外键有关 CREATE TABLE Table(特殊的主键 serial NOT NULL,外键 …

ICML2024 定义新隐私保护升级:DP-BITFIT新型微调技术让AI模型学习更安全

DeepVisionary 每日深度学习前沿科技推送&顶会论文分享&#xff0c;与你一起了解前沿深度学习信息&#xff01; 引言&#xff1a;差分隐私在大模型微调中的重要性和挑战 在当今的深度学习领域&#xff0c;大型预训练模型的微调已成为提高各种任务性能的关键技术。然而&am…

Multi-objective reinforcement learning approach for trip recommendation

Multi-objective reinforcement learning approach for trip recommendation A B S T R A C T 行程推荐是一项智能服务&#xff0c;为游客在陌生的城市提供个性化的行程规划。 它旨在构建一系列有序的 POI&#xff0c;在时间和空间限制下最大化用户的旅行体验。 将候选 POI 添…

[OpenGL] 法线贴图

目录 一 为什么要使用法线贴图 二 二种不同法线方式的使用 2.1 插值法线 2.1 法线贴图 本章节源码 点击此处 一 为什么要使用法线贴图 法线贴图我们可以使用更少的顶点表现出同样丰富的细节。高精度网格和使用法线贴图的低精度网格几乎区分不出来。所以法线贴图不仅看起来…

从ES到ClickHouse,Bonree ONE平台更轻更快!

本文字数&#xff1a;8052&#xff1b;估计阅读时间&#xff1a;21 分钟 作者&#xff1a;博睿数据 李骅宸&#xff08;太道&#xff09;& 娄志强&#xff08;冬青&#xff09; 本文在公众号【ClickHouseInc】首发 本系列第一篇内容&#xff1a; 100%降本增效&#xff01;…

windows安装kafka环境

1.安装jdk8 参考教程java8安装教程_java8u371安装教程-CSDN博客 下载kafak安装包&#xff1a; kafka_2.12-3.6.1.tgz 解压&#xff1a; 启动ZooKeeper软件&#xff0c;kafka内部已近集成了该软件。 进入Kafka解压缩文件夹的config目录&#xff0c;修改zookeeper.properti…

SpringCloud系列(22)--Ribbon默认负载轮询算法原理及源码解析

前言&#xff1a;在上一篇文章中我们介绍了如何去切换Ribbon的负载均衡模式&#xff0c;而本章节内容则是介绍Ribbon默认负载轮询算法的原理。 1、负载轮询算法公式 rest接口第N次请求数 % 服务器集群总数 实际调用服务器下标&#xff08;每次服务器重启后rest接口计数从1开始…

HTML静态网页成品作业(HTML+CSS)——动漫海绵宝宝介绍网页(5个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;未使用Javacsript代码&#xff0c;共有5个页面。 二、作品演示 三、代…

外卖小程序开发指南:从源码开始构建高效的外卖平台

今天&#xff0c;笔者将为您详细讲解如何从源码开始构建一个高效的外卖小程序&#xff0c;帮助您快速进入这一蓬勃发展的市场。 一、需求分析与设计 需求分析包括&#xff1a; 1.用户需求 2.市场需求 3.技术需求 二、前端开发 以下是开发步骤&#xff1a; -使用微信开发…

听说部门来了个00后测试开发,一顿操作给我整麻了

公司新来了个同事&#xff0c;听说大学是学的广告专业&#xff0c;因为喜欢IT行业就找了个培训班&#xff0c;后来在一家小公司实习半年&#xff0c;现在跳槽来我们公司。来了之后把现有项目的性能优化了一遍&#xff0c;服务器缩减一半&#xff0c;性能反而提升4倍&#xff01…

labelme的使用

创建虚拟环境 听说是要用这个3.6版本的python环境 conda create --namelabelme python3.6激活虚拟环境 activate labelme下载labelme pip install labelme #安装labelme组件启动labelme 在你打开文件的时候推荐还是自己先建立一个label.txt 把自己要分的类别放进去 label.…

【CSP CCF】202104-2 邻域均值

题目 过程 前缀和 定义 假定一个数组&#xff0c;前缀和就是该元素前所有元素和。也就是如果我们舌钉一个数组s为前缀和数组&#xff0c;那么s[3]就是我们原数组前三个元素之和。 优势 降低计算复杂度。 如果我们要求一段区间的和&#xff0c;那么我们用普通数组要从第一…

Linux驱动开发笔记(二) 基于字符设备驱动的I/O操作

文章目录 前言一、设备驱动的作用与本质1. 驱动的作用2. 有无操作系统的区别 二、内存管理单元MMU三、相关函数1. ioremap( )2. iounmap( )3. class_create( )4. class_destroy( ) 四、GPIO的基本知识1. GPIO的寄存器进行读写操作流程2. 引脚复用2. 定义GPIO寄存器物理地址 五、…

一个 Go 实现的跨平台 GUI 框架 Fyne

今天&#xff0c;推荐一个 Go 实现的 GUI 库 - fyne。 Go 官方也没有提供标准的 GUI 框架&#xff0c;在 Go 实现的几个 GUI 库中&#xff0c;Fyne 算是最出色的&#xff0c;它有着简洁的API、支持跨平台能力&#xff0c;且高度可扩展。这也就是说&#xff0c;Fyne 是可以开发…

如果直升机一直在空中悬停,24小时后能否绕行地球一圈?

直升机悬停在空中&#xff0c;似乎给了我们一种静止的错觉。但如果直升机一直保持这种状态&#xff0c;24小时后&#xff0c;它是否能够神奇地绕地球一圈&#xff1f; 地球自转&#xff1a;直升机悬停的无形锁链 问题的答案并非像表面上看起来那样简单。要解答这个问题&#…

Win10玩红警黑屏有声音的解决方法

Win10玩红警黑屏怎么解决&#xff1f;红色警戒&#xff0c;可以说是一款深受青少年朋友喜爱的网游&#xff0c;但是&#xff0c;当我们在使用win10电脑运行红色警戒的时候免不了会出现不兼容、权限不足等问题。相信玩过红警的小伙伴都有遇到过黑屏的问题&#xff0c;那该怎么解…

弱密码系统登录之后强制修改密码

在你登录的时候&#xff0c;获取到弱密码&#xff0c;然后将他存到vuex里面&#xff0c;在登录进去之后&#xff0c;index页面再去取&#xff0c;思路是这样的 一、vuex里面定义密码字段 我是直接在user.js里面写的 import { login, logout, getInfo } from /api/login impo…

SQLmap学习以及题解运用

1.简介 SQLmap是一款开源的SQL注入工具&#xff0c;用于检测和利用Web应用程序的SQL注入漏洞。SQLmap支持多种数据库管理系统&#xff0c;包括MySQL、Oracle、PostgreSQL、Microsoft SQL Server、SQLite等&#xff0c;并支持各种不同的操作系统和平台。 这里主要分为四大部分…

计网(部分在session学习章)

TCP/UDP TCP:面向连接,先三次握手建立连接,可靠传输。 UDP:无连接,不可靠,传递的快。 TCP可靠传输 1.分块编号传输; 2.校验和,校验首部和数据的检验和,检测数据在传输中的变化; 3.丢弃重复数据; 4.流量控制,TCP 利⽤滑动窗⼝实现流量控制。TCP的拥塞控制采⽤…