当前位置: 首页 > news >正文

JVM-JVM中对象的生命周期

申明:文章内容是本人学习极客时间课程所写,文字和图片基本来源于课程资料,在某些地方会插入一点自己的理解,未用于商业用途,侵删。
原资料地址:课程资料

对象的创建

在这里插入图片描述

常量池检查:检查new指令是否能在常量池中定位到这个类的符号引用,检查类之前是否被加载过。如果已经加载则直接使用,否则需要进行加载。
分配内存空间
有两种方式:

  • 指针碰撞 由Serial 和 ParNew去回收
  • 空闲列表 有CMS和Mark-Sweep回收
    必要信息的设置:对象的元数据,对象哈希码,GC分代年龄 -> 对象头
    在这里插入图片描述
    指针碰撞往往是一片连续的区域,空闲列表是非连续的。
    在这里插入图片描述
    内存分配存在的问题
    1 线程安全问题,因为堆是共享的,如果多个线程同时执行可能存在线程安全问题。
    解决方案:
    1) 通过CAS乐观锁:IVM虚拟机采用CAS失败重试的方式保证更新操作的原子性
    2)TLAB (Thread LocalAllocation Buffer) 本地线程分配缓存,预分配(也就是先给这个线程分配一个私有的内存,这样就不会有并发问题)
    分配主流程:首先从TLAB里面分配,如果分配不到,再使用CAS从堆里面划分

分配内存分配是是老年代还是年轻代
内存的分配大多数new出来的对象都是新生代,但是也有部分会去到老年代(比如大对象,在新生代无法放下)。
必要信息设置
对象类的元数据,对象哈希码,GC分带年龄(存储在对象头中)

对象进入老年代

在这里插入图片描述
进入老年代的条件
1 存活年龄太大,默认超过15次【-XX:MaxTenuringThreshold】(GC过程中会讲)
在这里插入图片描述
1 在MinorGC的时候存活的对象会被复制到幸存区域年龄 + 1 2 下一次GC的时候幸存取的对象和Eden的对象存活的对象会被复制到第二块幸存区域 年龄 + 1 3 这样来回复制如果对象的年龄大于15就会放入老年代,可以修改这个值
2 动态年龄判断:MinorGC之后,发现Survivor区中的一批对象的总大小大于了这块Survivor区的50%,那么就会将此时大于等于这批对象年龄最大值的所有对象,直接进入老年代。
-XX:TargetSurvivorRatio可以指定
举个栗子:Survivor区中有一批对象,年龄分别为年龄1+年龄2+年龄n的多个对象,对象总和大小超过了Survivor区域的50%,此时就会把年龄n及以上的对象都放入老年代。
为什么会这样?
希望那些可能是长期存活的对象,尽早进入老年代。

3 大对象直接进入老年代:前提是Serial和ParNew收集器
大对象可以通过这个参数去配置: -XX:PretenureSizeThreshold 一般设置为1M
举个栗子:字符串或数组
为什么会这样?为了避免大对象分配内存时的复制操作降低效率。避免了Eden和Survivor区的复制

空间担保机制:当新生代无法分配内存的时候,我们想把新生代的老对象转移到老年代,然后把新对象放入腾空的新生代。此种机制我们称之为内存担保。
4 MinorGC后,存活对象太多无法放入Survivor

  • MinorGC前,判断老年代可用内存是否小于新时代对象全部对象大小,如果小于则继续判断老年代可用内存大小是否小于之前每次MinorGC后进入老年代的对象平均大小
    如果是,则会进行一次FullGC,判断是否放得下,放不下OOM
    如果否(代表老年代能放下),则会进行MinorGC:
    MinorGC后,剩余存活对象小于Survivor区大小,直接进入Survivor区
    MinorGC后,剩余存活对象大于Survivor区大小,但是小于老年代可用内存,直接进入老年代
    MinorGC后,剩余存活对象大于Survivor区大小,也大于老年代可用内存,进行FullGC
    FullGC之后,任然没有足够内存存放MinorGC的剩余对象,就会OOM
    在这里插入图片描述

案例1,大对象直接进入老年区:

// -Xmx60m -Xms60m -XX:NewRatio=2 -XX:SurvivorRatio=8 -XX:+PrintGCDetails
// Xmx 程序运行时最大内存大小
// Xms 程序启动时最大内存大小
// NewRatio 年轻代和老年代的比例为1:2
// SurvivorRatio survivor区域和eden 区域的内存比例 1 : 8
// PrintGCDetails 打印详细日志
public static void main(String[] args) {byte[] buffer = new byte[1024*1024*20];}

在这里插入图片描述
在这里插入图片描述
由这个例子我们可以得出结论因为年轻代的内存总共也就18M左右导致年轻代无法存放我们创建的20M大小的数组,所以直接放入到了老年代。
案例2:

// -Xmx600m -Xms600m -XX:+PrintGCDetails
public class HeapInstance {public static void main(String[] args) {List<Picture> list = new ArrayList<>();while (true) {try {Thread.sleep(20);} catch (InterruptedException e) {e.printStackTrace();}list.add(new Picture(new Random().nextInt(1024 * 1024)));}}
}public class Picture {private byte[] pixels;public Picture(int length){this.pixels = new byte[length];}
}

与前面的描述呼应,进行三次FG后任然无法分配内存,则OOM。整个过程大致是这样,我们不断地创建对象,然后Eden区逐渐被占满,从而一部分对象复制到幸存区,然后幸存区(这个过程中会有动态年龄的判断来回复制)放不下了进入老年区,直到老年区也无法放下就内存溢出。
在这里插入图片描述

案例3,动态内存担保机制的演示:
空间担保机制:当新生代无法分配内存的时候,我们想把新生代的老对象转移到老年代,然后把新对象放入腾空的新生代。此种机制我们称之为内存担保。

// -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:+UseSerialGC
// 初始内存  最大内存  年轻第空间  
public class Demo {private static final int _1MB = 1024 * 1024;public static void main(String[] args) {memoryAllocation();}public static void memoryAllocation() {byte[] allocation1, allocation2, allocation3, allocation4;allocation1 = new byte[1 * _1MB];//1Mallocation2 = new byte[1 * _1MB];//1Mallocation3 = new byte[1 * _1MB];//1Mallocation4 = new byte[5 * _1MB];//5MSystem.out.println("完毕");}
}

JVM参数
在这里插入图片描述
可以看到老年代存了一个大约3M的对象,年轻代存大约6M的一个对象。
那么它执行的流程是这样的,前面3M的对象在eden区域分配后,后面来了一个5M的对象,发现内存不足,于是将之前3M 的数据移入了老年代,之后将5M的数据放入新生代,这就是内存担保机制。

http://www.lryc.cn/news/301227.html

相关文章:

  • RegExp正则表达式左限定右限定左右限定,预查询,预查寻,断言 : (?<= , (?= , (?<! , (?!
  • 相机图像质量研究(30)常见问题总结:图像处理对成像的影响--重影
  • 问题记录——c++ sort 函数 和 严格弱序比较
  • 《Go 简易速速上手小册》第9章:数据库交互(2024 最新版)
  • redis的hash数据结构底层简记
  • 清除Django的管理员admin站点中“Recent Actions“最近活动面板上的所有信息
  • 【JVM篇】ThreadLocal中为什么要使用弱引用
  • Stable Diffusion教程——stable diffusion基础原理详解与安装秋叶整合包进行出图测试
  • 【JavaEE】_线程与多线程的创建
  • 【前端工程化面试题】如何优化提高 webpack 的构建速度
  • 免费chatgpt使用
  • OpenCV识别人脸案例实战
  • VOSK——离线语音库
  • ELAdmin 隐藏添加编辑按钮
  • 浅谈Websocket
  • JavaScript闭包详细介绍
  • pytorch神经网络入门代码
  • 代码随想录算法训练营第三十四天|860.柠檬水找零 406.根据身高重建队列 452. 用最少数量的箭引爆气球
  • Ditto:提升剪贴板体验的宝藏软件(复制粘贴效率翻倍、文本处理好助手)
  • 【自然语言处理-工具篇】spaCy<2>--模型的使用
  • Java之通过Jsch库连接Linux实现文件传输
  • Nginx七层负载均衡之动静分离
  • 305_C++_定义了一个定时器池 TimerPool 类和相关的枚举类型和结构体
  • 大整数因数分解工具——yafu
  • 非关系型数据库(NOSQL)和关系型数据库(SQL)区别详解
  • 7.Cloud-GateWay
  • 【Linux】Framebuffer 应用
  • markdown绘制流程图相关代码片段记录
  • 云计算基础-计算虚拟化-CPU虚拟化
  • MySQL数据库⑪_C/C++连接MySQL_发送请求