『』你写的Java对象究竟占多少内存?

概述
Java 作为一个面向对象语言 , 给我们带来了多态 , 继承 , 封装等特性 , 使得我们可以利用这些特性很轻松的就能构建出易于扩展 , 易于维护的代码 。作为一个Javaer , 天天搞“对象” , 那你写的对象究竟占用了多少内存呢?我们来看看你的“对象”是如何“败家”的 。本文环境:jdk1.8_64Java 对象头内存模型
我们先来看看 , 一个Java 对象的内存模型是怎么样的?由于我们的虚拟机是分为32位和64位 , 那肯定它们的模型也是有区别的 , 下面我列出列32位虚拟机和64位虚拟机下的Java对象头内存模型 。
『』你写的Java对象究竟占多少内存?
文章图片

文章图片

『』你写的Java对象究竟占多少内存?
文章图片

文章图片

『』你写的Java对象究竟占多少内存?
文章图片

文章图片

因为笔者的本地环境是jdk1.8,64位虚拟机 , 这里我以64位虚拟机(开启指针压缩)来分析 , 因为默认情况下 , jdk1.8 在64位虚拟机默认开启指针压缩 。
Java 对象头主要包括两部分 , 第一部分就是 Mark Word , 这也是 Java 锁实现原理中重要的一环 , 另外一部分是 Klass Word 。
Klass Word 这里其实是虚拟机设计的一个oop-klass model模型 , 这里的OOP是指Ordinary Object Pointer(普通对象指针) , 看起来像个指针实际上是藏在指针里的对象 。而 klass 则包含 元数据和方法信息 , 用来描述 Java 类 。它在64位虚拟机开启压缩指针的环境下占用 32bits 空间 。
Mark Word 是我们分析的重点 , 这里也会设计到锁的相关知识 。Mark Word 在64位虚拟机环境下占用 64bits 空间 。整个Mark Word的分配有几种情况:
未锁定(Normal): 哈希码(identity_hashcode)占用31bits , 分代年龄(age)占用4 bits , 偏向模式(biased_lock)占用1 bits , 锁标记(lock)占用2 bits , 剩余26bits 未使用(也就是全为0)
可偏向(Biased): 线程id 占54bits , epoch 占2 bits , 分代年龄(age)占用4 bits , 偏向模式(biased_lock)占用1 bits , 锁标记(lock)占用2 bits , 剩余 1bit 未使用 。
轻量锁定(Lightweight Locked): 锁指针占用62bits , 锁标记(lock)占用2 bits 。
重量级锁定(Heavyweight Locked):锁指针占用62bits , 锁标记(lock)占用2 bits 。
GC 标记:标记位占2bits , 其余为空(也就是填充0)
以上就是我们对Java对象头内存模型的解析 , 只要是Java对象 , 那么就肯定会包括对象头 , 也就是说这部分内存占用是避免不了的 。所以 , 在笔者64位虚拟机 , Jdk1.8(开启了指针压缩)的环境下 , 任何一个对象 , 啥也不做 , 只要声明一个类 , 那么它的内存占用就至少是96bits , 也就是至少12字节 。验证模型
我们来写点代码来验证一下上述的内存模型 , 这里推荐openjdk的jol工具 , 它可以帮助你查看对象内存的占用情况 。
首先添加maven依赖
org.openjdk.jol
jol-core
0.10
我们先来看看 , 如果只是新建一个普通的类 , 什么属性也不添加 , 占用的空间是多少?/*** @description:* @author: luozhou* @create: 2020-02-26 10:00**/ public class NullObject { }
按照我们之前的Java对象内存模型分析 , 一个空对象 , 那就是只有一个对象头部 , 在指针压缩的条件下会占用 96 bit , 也就是12byte 。
运行工具查看空间占用public static void main(String[] args) {System.out.println(ClassLayout.parseInstance(new NullObject()).toPrintable());}


推荐阅读