学习笔记-JVM-对象结构及生命周期

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

对象的创建流程

在这里插入图片描述

常量池检查:检查new指令是否能在常量池中定位到这个类的符号引用,检查类之前是否被加载过

分配内存空间
有两种方式:

指针碰撞: GC不带压缩功能,Serial和ParNew

空闲列表: GC带压缩功能,CMS
注:内存的分配大多数new出来的对象都是新生代,但是也有部分会去到老年代。
在这里插入图片描述
指针碰撞往往是一片连续的区域,空闲列表是非连续的。
在这里插入图片描述
*内存分配存在的问题
1 线程安全问题,因为堆是共享的,如果多个线程同时执行可能存在线程安全问题。
解决方案:
1) 通过CAS乐观锁:IVM虚拟机采用CAS失败重试的方式保证更新操作的原子性
2)TLAB (Thread LocalAllocation Buffer) 本地线程分配缓存,预分配

分配主流程:首先从TLAB里面分配,如果分配不到,再使用CAS从堆里面划分

必要信息设置
对象类的元数据,对象哈希码,GC分带年龄(存储在对象头中)

进入老年代

在这里插入图片描述
进入老年代的条件:

1 存活年龄太大,默认超过15次【-XX:MaxTenuringThreshold】

2 动态年龄判断:MinorGC之后,发现Survivor区中的一批对象的总大小大于了这块Survivor区
的50%,那么就会将此时大于等于这批对象年龄最大值的所有对象,直接进入老年代。
举个栗子:Survivor区中有一批对象,年龄分别为年龄1+年龄2+年龄n的多个对象,对象总和大小超过了Survivor区域的50%,此时就会把年龄n及以上的对象都放入老年代。

为什么会这样?希望那些可能是长期存活的对象,尽早进入老年代。
-XX:TargetSurvivorRatio可以指定

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

3 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("完毕");}
}

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

对象内存布局

对象里的三个区:

  1. 对象头(Header):Java对象头占8byte。如果是数组则占12byte。因为JVM里数组size需要使用4byte存储。
    标记字段MarkWord:
    用于存储对象自身的运行时数据,它是synchronized实现轻量级锁和偏向锁的关键。
    默认存储:对象HashCode、GC分代年龄、锁状态等等信息。
    为了节省空间,也会随着锁标志位的变化,存储数据发生变化。下面画图解释
    类型指针KlassPoint:
    是对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例
    开启指针压缩存储空间4byte,不开启8byte。
    JDK1.6+默认开启
    **数组长度:**如果对象是数组,则记录数组长度,占4个byte,如果对象不是数组则不存在。
    **对齐填充:**保证数组的大小永远是8byte的整数倍。

  2. 实例数据(Instance Data):生成对象的时候,对象的非静态成员变量也会存入堆空间

  3. 对齐填充(Padding):JVM内对象都采用8byte对齐,不够8byte的会自动补齐。

在这里插入图片描述
标记字段的结构:
在这里插入图片描述
案例1:

<dependency><groupId>org.openjdk.jol</groupId><artifactId>jol-core</artifactId><version>0.9</version>
</dependency>
 Object o = new Object();System.out.println("new Object:" +ClassLayout.parseInstance(o).toPrintable());

在这里插入图片描述
注:首先对象头是包含MarkWord和类型指针这两部分信息的;
开启指针压缩的情况下,存放Class指针的空间大小是4字节,MarkWord是8字节,对象头为12字节;
新建Object对象,会在内存占用16个字节,其中Header占12个(MarkWord占8个+KlassPoint占4个),没有实例数据,补充对齐4个。
结论:对象大小 = 对象头12 + 实例数据0 + 对齐填充4 = 16 bytes
在这里插入图片描述
案例2:

public class TT {public static void main(String[] args) {Hero a = new Hero();System.out.println("new A:"+ClassLayout.parseInstance(a).toPrintable());a.setFlag(true);a.setI(1);a.setStr("ABC");System.out.println("赋值 A:"+ClassLayout.parseInstance(a).toPrintable());}
}

在这里插入图片描述

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

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

相关文章

6.利用matlab完成 符号矩阵的秩和 符号方阵的逆矩阵和行列式 (matlab程序)

1.简述 利用M文件建立矩阵 对于比较大且比较复杂的矩阵&#xff0c;可以为它专门建立一个M文件。下面通过一个简单例子来说明如何利用M文件创建矩阵。 例2-2 利用M文件建立MYMAT矩阵。(1) 启动有关编辑程序或MATLAB文本编辑器&#xff0c;并输入待建矩阵&#xff1a;(2) 把…

LeetCode面向运气之Javascript—第121题-买卖股票的最佳时机-97.77%

LeetCode第121题-买卖股票的最佳时机 题目要求 给定一个数组prices &#xff0c;它的第i个元素prices[i]表示一支给定股票第i天的价格。 你只能选择某一天买入这只股票&#xff0c;并选择在未来的某一个不同的日子卖出该股票。设计一个算法来计算你所能获取的最大利润。 返回…

【云原生】Kubernetes 概述

Kubernetes 概述 1.Kubernetes 简介 Kubernetes 是一个可移植的、可扩展的、用于管理容器化工作负载和服务的开源平台&#xff0c;它简化&#xff08;促进&#xff09;了声明式配置和自动化。它有一个庞大的、快速增长的生态系统。Kubernetes 的服务、支持和工具随处可见。 K…

Jay17 2023.8.12日报

8.12 今天做了2题&#xff0c;CTFshow 红包挑战8&#xff08;PHP create_function()&#xff09;和BUU [RoarCTF 2019]Easy Java&#xff08;web.xml泄露&#xff09;。 此外一直在打NepCTF&#xff0c;出了一题&#xff08;ez_java_checkin&#xff09;简单了解了java中shri…

02 - git 文件重命名

第一种方式&#xff1a; mv kongfu_person.txt kongfu.txt git add .第二种方式&#xff1a; git mv kongfu_person.txt kongfu.txt

Jmeter请求接口返回值乱码解决

乱码示例 解决步骤&#xff1a; 1.打开Jmeter安装目录下的bin目录&#xff0c;找到jmeter.properties 2.使用记事本或其他编译工具打开jmeter.properties文件&#xff0c;然后全局搜索sampleresult.default.encoding 3.在文件中添加sampleresult.default.encodingutf-8,保存…

TSINGSEE青犀视频安防监控视频平台EasyCVR设备在线,视频无法播放的原因排查

可支持国标GB28181、RTMP、RTSP/Onvif、海康Ehome、海康SDK、大华SDK、宇视SDK等多种协议接入的安防监控视频平台EasyCVR基于云边端一体化架构&#xff0c;具有强大的数据接入、处理及分发能力&#xff0c;可在复杂的网络环境中&#xff0c;将分散的各类视频资源进行统一汇聚、…

【CSS学习笔记】

学习内容 1.css是什么 2.CSS怎么用&#xff08;快速入门&#xff09; 3.CSS选择器&#xff08;重点 难点&#xff09; 4.美化页面&#xff08;文字、阴影、超链接、列表、渐变…&#xff09; 5.盒子模型 6.浮动 7.定位 8.网页动画&#xff08;特效&#xff09; 1.什么是CSS C…

【计算机视觉|生成对抗】用深度卷积生成对抗网络进行无监督表示学习(DCGAN)

本系列博文为深度学习/计算机视觉论文笔记&#xff0c;转载请注明出处 标题&#xff1a;Unsupervised Representation Learning with Deep Convolutional Generative Adversarial Networks 链接&#xff1a;[1511.06434] Unsupervised Representation Learning with Deep Conv…

利用ApiPost实现Mock Server服务

APIPOST可以让你在没有后端程序的情况下能真实地返回接口数据&#xff0c;你可以用APIPOST实现项目初期纯前端的效果演示&#xff0c;也可以用APIPOST实现开发中的数据模拟从而实现前后端分离。在使用APIPOST之前&#xff0c;你的团队实现数据模拟可能是下面的方案中的一种或者…

Linux命令200例:pwd用于显示当前工作目录的绝对路径

&#x1f3c6;作者简介&#xff0c;黑夜开发者&#xff0c;全栈领域新星创作者✌。CSDN专家博主&#xff0c;阿里云社区专家博主&#xff0c;2023年6月csdn上海赛道top4。 &#x1f3c6;数年电商行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责人。 &…

数字化时代,选择商业智能BI解决80%数据问题

数据是需要有人来照料、培养的&#xff0c;如果企业没有完善的数据治理方案&#xff0c;就很难保障数据的质量&#xff0c;进而导致数据无法利用&#xff0c;让这些辛苦积累的数据失去了价值。 数据治理目标 数据从业务活动中产生&#xff0c;也会深刻影响到业务本身。 对于…