thinkphp 网站根目录地址,自己做网站需要什么程序,建网站专业,南昌企业做网站一、说一说JVM中对象的内存布局#xff1f;new一个对象到底占多大内存#xff1f;
话不多说#xff0c;看下图#xff0c;对象的内存布局图 一个对象的内存布局主要由三部分组成#xff1a;对象头#xff08;Object Header#xff09;、实例数据#xff08;Instance D…一、说一说JVM中对象的内存布局new一个对象到底占多大内存
话不多说看下图对象的内存布局图 一个对象的内存布局主要由三部分组成对象头Object Header、实例数据Instance Data和对齐填充Padding。下面分别介绍这三部分
对象头Object Header
Mark Word存储对象自身的运行时数据如哈希码、GC分代年龄、锁状态标志等。这部分信息是与对象自身相关的元数据。类型指针指向对象类型数据的指针即该对象属于哪个类的实例。这个地址用于访问类型数据区中的类信息包括方法表和其他静态变量。
实例数据Instance Data
这一部分存放着对象真正有效信息也就是程序中定义的各种类型的字段内容。这些字段按照从父类到子类的顺序分配内存同时相同宽度的字段会被分配在一起以优化空间使用效率。此外JVM还可能对字段进行重新排序以进一步优化性能这一过程称为字段排列Field Layout。
对齐填充Padding
JVM要求对象的起始地址必须是8字节的整数倍这是为了提高CPU缓存命中率和访问速度。
而数组类型的对象还有4个字节的数组长度字段所有new一个对象需要的内存大小为
8byte(对象头) 4byte(类型指针) 实例数据 填充字段 4byte数组长度(若为数组类型)
二、阐述对象的内存分配策略
整体策略如下图所示 我们来剖析一下
首先判读是否在栈上分配
在现代JVM中编译器可能会执行逃逸分析来判断新创建的对象是否只在当前方法或线程内使用。如果一个对象不会“逃逸”出方法的作用域或者被其他线程引用那么它可以安全地分配在栈上而不是堆上这被称为标量替换Scalar Replacement。这种优化可以减少垃圾回收的压力并提高性能。
大对象直接进入老年代
如果对象的大小超过了某个阈值可以通过-XX:PretenureSizeThreshold参数配置JVM可能会决定直接将该对象分配到老年代以避免因频繁复制而增加的GC开销。对于非常大的对象这样的分配策略能够提升性能。
线程本地分配Thread Local Allocation Buffer, TLAB
为了减少多线程环境下的锁竞争每个线程都有自己的小块内存区域(在堆中)称为TLAB。当一个线程需要分配对象时它首先尝试在自己的TLAB中分配。只有当TLAB空间不足时才会触发全局同步操作以分配新的TLAB或者直接从共享堆中分配。
对象优先分配到Eden区
如果对象不适合上述任何一种特殊处理则按照标准的内存分配流程进行即在年轻代的Eden区分配。如果Eden区没有足够的空间就会触发一次Minor GC若GC后仍无足够空间可能需要晋升部分对象到老年代甚至引发Full GC。
三、new一个对象都有哪些步骤
我们来看对象的创建过程如下图 1.类加载检查
JVM首先检查该类是否已经被加载到内存中。如果尚未加载则会触发类加载过程包括加载、链接验证、准备、解析和初始化。
2.分配内存
为新对象分配内存空间。这一步骤涉及到如何从堆内存中划分出足够的空间给新对象。内存分配的方式取决于JVM的实现和配置例如快速失败分配bump-the-pointer、线程本地分配缓冲区TLAB, Thread Local Allocation Buffer等。分配过程中还需要考虑对象的对齐填充确保对象占用的内存是8字节的整数倍以及处理并发情况下的线程安全问题。
3.内存空间初始化(初始化零值)
在分配完内存后JVM会对对象的实例变量进行零初始化zero-initialization即所有数值型字段被设为0或0.0引用类型字段被设为nullboolean类型字段被设为false。
4.设置(对象头)
初始化对象头的信息如哈希码、GC分代年龄、锁状态标志等并设置指向类元数据的指针以便知道对象属于哪个类。
5.对象初始化(执行构造函数)
调用类的构造方法来初始化对象的状态。构造方法可以设置成员变量的具体值并执行其他必要的初始化操作。这是用户代码控制的部分程序员可以在构造方法中编写自定义逻辑。