首页 > 编程知识 正文

c++对象内存模型,java内存计算

时间:2023-05-04 20:09:57 阅读:14733 作者:2691

由于面试官的势利,很多人都很了解jvm的内存模型,但你知道我们经常从new出来的对象,比如new Object (),那个内存模型吗? 本文带你进入对象内部,真正了解你最熟悉、最不熟悉的对象。

一、对象内存模型先看上图,简单易懂:

再看jvm源码:

classoopdesc { friendclassvmstructs; friend class JVMCIVMStructs; private: //目标头volatile jldwtOop _jldwt; //元数据union _metadata { //对应的Klass对象Klass* _klass; narrowKlass _compressed_klass; } _metadata; 在——3354————3354335433543354——335433543354335433543—— JVM中,所有对象都是由oop对象编写的,具有两个重要的子类:

instanceOopDesc (用于描述常规实例对象的arrayOopDesc )用于描述数组对象的二,内存模型分析对象头(Object Header ),我们常说的对象头主要是二

jldwtword :存储对象自身的运行时数据,稍后pointer: 即指向当前对象的类的元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例并非所有虚拟机实现都需要在对象数据中保留类型指针。 也就是说,搜索对象的元数据信息不需要通过对象本身。 对于数组,对象标头还包含用于存储数组长度的数据。 因为虚拟机可以根据常规Java对象的元数据信息确定Java对象的大小,但不能根据数组的元数据确定数组的大小。 实例数据:实例数据、对象实际存储的有效信息,或从自身或父类继承的属性。

填充:对齐填充。 在HotSpot VM的自动内存管理系统中,对象的起始地址必须是8字节的整数倍,换言之,对象的大小必须是8字节的整数倍,因此对象实例数据部分通过对齐填充进行补充,从而实现对象的

三、对象头的奥义陈规,先看上图,一目了然:

引人注目的可乐Word被设计为非固定的数据结构,用于在非常小的空间中存储尽可能多的信息,根据对象的状态回收自己的存储空间。 在对象的状态不同的情况下,即,在未锁定、欧洲、轻型锁定、重量锁定、GC状态的情况下,分别存储不同的内容,例如,在未锁定的情况下,存储对象的hashcode对象分代年龄状态位001

注:上图显示的是一个32位JVM和64位JVM在打开JVM参数- xx : usecompressedclasspointers后的结构图,默认情况下处于选中状态。 要禁用此选项,请设置JVM参数- xx :-usecompressedclasspointers如果关闭压缩,对象标头将占用8字节、64位。 结构图如下。

打开压缩后,jvm可以在创建大量对象进程时节省大量空间,并间接提高内存利用率。 同样-XX: UseCompressedOops,常规对象指针压缩在默认情况下也处于启用状态。

四.如锁定升级位置所述,目标头在不同的锁定状态下存储不同的数据。 那么,这种状态会发生什么变化呢? 偏转锁定是什么? 轻型摇滚是什么时候? 重型摇滚是什么时候? 这与锁定的过程有关。 这里以32位的对象磁头为对象。

首先,让我们来看看摇滚的基本概念。偏向锁。 当线程调用此对象时,jldwt word会在23位中记录指向当前线程的指针,以指示此锁定当前属于该线程。 同时偏转锁定位从0变为1;轻量级锁:当另一线程正在竞争锁定时,释放偏转锁定; 存储在30位中的是指向堆栈中锁定记录的指针,当另一个线程来需要竞争锁定时,(线程的线程堆栈中有LR(lockrecord ),竞争锁定,谁将其锁定,CAS

**重量锁定:根据**线程的不同,旋转次数超过10次,或者有超过CPU线程一半的线程在等待。 在JDK1.6之后,JVM被自适应地选择为自己控制上述参数。 把锁升级为重量锁。 女性化的可乐word的30位指向重型摇滚指针。 (重型锁定需要内核的批准。 线程进入应锁定的队列,在队列中等待,不消耗cpu。锁降级:仅在特定情况下发生,例如在GC时发生,所以意义不大。

锁定升级的过程:

流程分析:

1 .线程a在进入同步代码块之前,检查吸引人的可乐Word线程ID是否与当前线程ID匹配,如果匹配(或线程a正在获取锁定对象),则使用CAS进行锁定或

2 .如果不匹配,重新检查是否为偏转锁定,否则,旋转等待解锁。

3 .检查线程是否存在(如果适用),如果不存在,则将线程ID设置为线程a的ID。 这种情况下也依然是偏转锁定。

4 .如果仍在,请暂停线程,同时将锁定标志位设置为00=轻量锁。 (将吸引人的可乐Word复制到线程的堆栈帧,并将吸引人的可乐Word锁定到堆栈帧

记录)。线程A自旋等待锁释放。
5.如果自旋次数到了该线程还没有释放锁,或者该线程还在执行,线程A还在自旋等待,这时又有一个线程B过来竞争这个锁对象,那么这个时候轻量级锁就会膨胀为重量级锁。重量级锁把除了拥有锁的线程都阻塞,防止CPU空转。
6.如果该线程释放锁,则会唤醒所有阻塞线程,重新竞争锁。

五、证明对象的内存模型

上面说了那么多理论,看起来有点道理,似懂非懂,那么怎么证明对象头的内存模型确实如文章所言,别急,我们来一步步研究

1.先引入maven依赖 <dependency> <groupId>org.openjdk.jol</groupId> <artifactId>jol-core</artifactId> <version>0.9</version> </dependency> 2.在代码中打印所对象 import org.openjdk.jol.info.ClassLayout;/** * @author ljx * @Description: 打印对象的内存模型 * @date 2021/8/26 4:50 下午 */public class ObjectMemoryModel { private static class Test { int i; long l; boolean b; String s = "快给博主点赞"; void m(){}; } public static void main(String[] args) { Test t = new Test(); final String s = ClassLayout.parseInstance(t).toPrintable(); System.out.println(s); }} 3.输出结果


解析:如图所示,jldwtword占用了8个字节,class pointer占用了四个字节,instance data占用了 int的4个字节+long的8个字节+boolean的1个字节+string对象引用的4个字节 = 共17个字节,此时总共29个字节,不是8个字节的倍数,所以补齐3个字节,即padding 是 3个字节。

参考文章:https://www.zhangshengrong.com/p/v710KvgpXM/

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。