学习笔记-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];//1M
        allocation2 = new byte[1 * _1MB];//1M
        allocation3 = new byte[1 * _1MB];//1M
        allocation4 = new byte[5 * _1MB];//5M
        System.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());
    }
}

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【设计模式——学习笔记】23种设计模式——中介者模式Observer(原理讲解+应用场景介绍+案例介绍+Java代码实现)

文章目录 案例引入案例一普通实现中介者模式 案例二 介绍基础介绍登场角色尚硅谷 《图解设计模式》 案例实现案例一&#xff1a;智能家庭类图实现 案例二&#xff1a;登录页面逻辑实现说明类图实现 总结文章说明 案例引入 案例一 普通实现 在租房过程中&#xff0c;客户可能…

2.5D游戏是如何做出来的呢,2.5D游戏快速制作教程

前言 【Unity实战篇 】 | 如何制作一款2.5D游戏&#xff0c;2.5D游戏制作案例一、2.5D 游戏概念二、绘制地图三、添加玩家动画和移动等操作四、视角配置4.1 调整摄像机与场景对象的角度4.2 增加镜头旋转功能 五、游戏效果展示 总结 前言 玩过游戏的朋友都知道&#xff0c;市面…

HarmonyOS NEXT,生命之树初长成

在不同的神话体系中&#xff0c;都有着关于生命之树的记载。 比如在北欧神话中&#xff0c;一株巨大的树木联结着九大世界&#xff0c;其被称为“尤克特拉希尔”Yggdrasill。在中国的《山海经》中&#xff0c;也有着“建木”的传说&#xff0c;它“有九欘&#xff0c;下有九枸&…

idea添加翻译插件并配置有道翻译

1、安装Translation插件 2、 创建有道云应用 有道智云控制台 3、设置idea 4、效果&#xff08;选中文本右键翻译&#xff0c;默认快捷键CtrlShiftY&#xff09;

安达发制造工业迈向智能化:APS高级计划排程助力提升生产效率

随着市场竞争的加剧&#xff0c;制造企业纷纷寻求提高生产效率和降低成本的方法。近年来&#xff0c;越来越多的制造企业开始采用APS(高级计划与排程)系统&#xff0c;以优化生产计划和排程&#xff0c;提高生产效率&#xff0c;并在竞争中取得优势。 现代制造业通常面临复杂的…

Idea中maven无法下载源码

今天在解决问题的时候想要下载源码&#xff0c;突然发现idea无法下载&#xff0c;这是真的蛋疼&#xff0c;没办法查看原因&#xff0c;最后发现问题的原因居然是因为Maven&#xff0c;由于我使用的idea的内置的Bundle3的Maven&#xff0c;之前没有研究过本地安装和内置的区别&…

ESP 32 蓝牙虚拟键盘链接笔记本电脑的键值问题

由于打算利用esp32 通过蓝牙链接电脑后实现一些特俗的键盘功能&#xff0c;所以就折腾了一下&#xff0c;折腾最耗费时间的却是键值问题&#xff0c;让一个20多年的老司机重新补充了知识 过程曲折就不说了&#xff0c;直接说结果。 我们通过网络搜索获取的键值和蓝牙模拟键盘传…

Leetcode-每日一题【剑指 Offer 11. 旋转数组的最小数字】

题目 把一个数组最开始的若干个元素搬到数组的末尾&#xff0c;我们称之为数组的旋转。 给你一个可能存在 重复 元素值的数组 numbers &#xff0c;它原来是一个升序排列的数组&#xff0c;并按上述情形进行了一次旋转。请返回旋转数组的最小元素。例如&#xff0c;数组 [3,4…

【论文阅读】对抗溯源图主机入侵检测系统的模仿攻击(NDSS-2023)

作者&#xff1a;伊利诺伊大学芝加哥分校-Akul Goyal、Gang Wang、Adam Bates&#xff1b;维克森林大学-Xueyuan Han、 引用&#xff1a;Goyal A, Han X, Wang G, et al. Sometimes, You Aren’t What You Do: Mimicry Attacks against Provenance Graph Host Intrusion Detect…

docker容器监控:Cadvisor +Prometheus+Grafana的安装部署

目录 Cadvisor PrometheusGrafana的安装部署 一、安装docker&#xff1a; 1、安装docker-ce 2、阿里云镜像加速器 3、下载组件镜像 4、创建自定义网络 二、部署Cadvisor 1、被监控主机上部署Cadvisor容器 2、访问cAdvisor页面 三、安装prometheus 1、部署Prometheus…

20230806将ASF格式的视频转换为MP4

20230806将ASF格式的视频转换为MP4 2023/8/6 18:47 缘起&#xff0c;自考中山大学的《计算机网络》&#xff0c;考试《数据库系统原理》的时候找到视频&#xff0c;由于个人的原因&#xff0c;使用字幕更加有学习效率&#xff01; 由于【重型】的PR2023占用资源较多&#xff0c…

Spring security之JWT

JWT 这里写目录标题 JWT一级目录二级目录三级目录1.什么是JWT 2.JWT的组成部分3.编码/解码4.特点5. 为什么使用JWT5.1传统的验证方式 5.2基于JWT的验证方式6.JWT进行登录验证6.1依赖安装6.2编写UserDetailServiceImpl类6.3编写UserDetailsImpl类6.4 实现config.SecurityConfig类…

算法与数据结构(二十二)动态规划解题套路框架

动态规划解题套路框架 此文只在个人总结 labuladong 动态规划框架&#xff0c;仅限于学习交流&#xff0c;版权归原作者所有&#xff1b; 动态规划问题&#xff08;Dynamic Programming&#xff09;应该是很多读者头疼的&#xff0c;不过这类问题也是最具有技巧性&#xff0c…

替换开源LDAP,某科技企业用宁盾目录统一身份,为业务敏捷提供支撑

客户介绍 某高科技企业成立于2015年&#xff0c;是一家深耕于大物流领域的人工智能公司&#xff0c;迄今为止已为全球16个国家和地区&#xff0c;120余家客户打造智能化升级体验&#xff0c;场景覆盖海陆空铁、工厂等货运物流领域。 该公司使用开源LDAP面临的挑战 挑战1 开源…

【用于全变分去噪的分裂布雷格曼方法】实施拆分布雷格曼方法进行总变异去噪研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

docker菜谱

DockerHub&#xff1a;https://hub.docker.com/ 记录docker常用软件安装&#xff0c;欢迎大家来投稿。&#x1f60e;&#x1f60e;&#x1f60e; 文章目录 1. Redis2. MariaDB 1. Redis dockerhub:https://hub.docker.com/_/redis 1、下载redis镜像&#xff1a; docker pull r…

【MFC】05.MFC第一大机制:程序启动机制-笔记

MFC程序开发所谓是非常简单&#xff0c;但是对于我们逆向人员来说&#xff0c;如果想要逆向MFC程序&#xff0c;那么我们就必须了解它背后的机制&#xff0c;这样我们才能够清晰地逆向出MFC程序&#xff0c;今天这篇文章就来带领大家了解MFC的第一大机制&#xff1a;程序启动机…

echarts 图表饼状图 实例

效果图&#xff1a; 代码&#xff1a; draw(data1, data2) {var option {// backgroundColor: rgb(10,36,68),color: [#F19611 ,#0095FE,#162D86,#0096FF,#05F8FF,#FFD985,#FACDAA,#F4A49E,#EE7B91,#E85285,#BE408C,#942D93,#171E6D,#1E3388,#27539B,#3073AE,#3993C2,#42B3D…

JVM如何调优

一、JVM内存模型及垃圾收集算法 1.根据Java虚拟机规范&#xff0c;JVM将内存划分为&#xff1a; New&#xff08;年轻代&#xff09; Tenured&#xff08;年老代&#xff09; 永久代&#xff08;Perm&#xff09; 其中New和Tenured属于堆内存&#xff0c;堆内存会从JVM启动参…

day0808

1.单链表实现约瑟夫环 #include "joseph.h" LoopLink list_create(int m) {LoopLink L (LoopLink)malloc(sizeof(Node));if(NULLL){printf("内存创建失败\n");return 0;}LoopLink qL;for(int i1; i<m; i){LoopLink p (LoopLink)malloc(sizeof(Node));…