java.lang.instrument: 一个Java对象占用多少字节?
一、对象头包括两部分信息:Mark Word(标记字段)和 Klass Pointer(类型指针)
1. Mark Word 用于存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程 ID、偏向时间戳等等。
JVM 对象头一般占用两个机器码,在 32-bit JVM 上占用 64bit, 在 64-bit JVM 上占用 128bit 即 16 bytes(暂不考虑开启压缩指针的场景)。
另外,如果对象是一个 Java 数组,那在对象头中还必须有一块用于记录数组长度的数据,因为虚拟机可以通过普通 Java 对象的元数据信息确定 Java 对象的大小,但是从数组的元数据中无法确定数组的大小。
对象需要存储的运行时数据很多,其实已经超出了32、64位 Bitmap 结构所能记录的限度,但是对象头信息是与对象自身定义的数据无关的额外存储成本,考虑到虚拟机的空间效率,Mark Word 被设计成一个非固定的数据结构以便在极小的空间内存储尽量多的信息,它会根据对象的状态复用自己的存储空间。
例如在 32 位的HotSpot 虚拟机中对象未被锁定的状态下,Mark Word 的 32个Bits 空间中的 25Bits 用于存储对象哈希码(HashCode),4Bits 用于存储对象分代年龄,2Bits 用于存储锁标志位,1Bit固定为0,在其他状态(轻量级锁定、重量级锁定、GC标记、可偏向)下对象的存储内容如下表所示。
|
存储内容 |
标志位 |
状态 |
|
对象哈希码、对象分代年龄 |
01 |
未锁定 |
|
指向锁记录的指针 |
00 |
轻量级锁定 |
|
指向重量级锁的指针 |
10 |
膨胀(重量级锁定) |
|
空,不需要记录信息 |
11 |
GC标记 |
|
偏向线程ID、偏向时间戳、对象分代年龄 |
01 |
可偏向 |
- Klass Pointer,即是对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。
二、UseCompressOops
通常64位JVM消耗的内存会比32位的大1.5倍,这是因为对象指针在64位架构下,长度会翻倍(更宽的寻址)。
对于那些将要从32位平台移植到64位的应用来说,平白无辜多了1/2的内存占用,这是开发者不愿意看到的。
幸运的是,从JDK 1.6 update14开始,64 bit JVM正式支持了 -XX:+UseCompressedOops 这个可以压缩指针,起到节约内存占用的新参数。
1. 什么是 OOP ?
OOP = “ordinary object pointer” 普通对象指针。
启用CompressOops后,会压缩的对象:
• 每个Class的属性指针(静态成员变量)
• 每个对象的属性指针
• 普通对象数组的每个元素指针
当然,压缩也不是万能的,针对一些特殊类型的指针,JVM是不会优化的。
比如指向PermGen的Class对象指针,本地变量,堆栈元素,入参,返回值,NULL指针不会被压缩。
2. 怎么启用?
在启动java时,加 -XX:+UseCompressedOops (需要jdk1.6.0_14)
3. CompressedOops的原理
当对象被读取时,解压,存入heap时,压缩。
4. 零基压缩优化(Zero Based Compressd Oops)
零基压缩是针对压解压动作的进一步优化。
它通过改变正常指针的随机地址分配特性,强制从零开始做分配(需要OS支持),进一步提高了压解压效率。
要启用零基压缩,你分配给JVM的内存大小必须控制在4G以上,32G以下。
如果小于4G,那么JVM会使用低虚拟地址空间(low virutal address space,64位下模拟32位),这样就不需要做压解压动作了。
而对于大于32G,将采用默认的随机地址分配特性,进行压解压。
5. 适用场景
CompressedOops,可以让跑在64位平台下的JVM,不需要因为更宽的寻址,而付出Heap容量损失的代价。
不过,它的实现方式是在机器码中植入压缩与解压指令,可能会给JVM增加额外的开销。
6. 效果
关闭压缩 启用压缩
基本类型 (int) 4 4
引用类型 (Integer) 4 8
数组(new Integer[0]) 16 24
/**
* -XX:+UseCompressedOops: mark/4 + metedata/8 + 4 = 16
* -XX:-UseCompressedOops: mark/8 + metedata/8 + 4 + padding/4 = 24
*/
class A {
int a;
} /**
* -XX:+UseCompressedOops: mark/4 + metedata/8 + 4 + 4 + padding/4 = 24
* -XX:-UseCompressedOops: mark/8 + metedata/8 + 4 + 4 = 24
*/
class B1 {
int a;
int b;
} /**
* -XX:+UseCompressedOops: mark/4 + metedata/8 + 4 + 4 + padding/4 = 24
* -XX:-UseCompressedOops: mark/8 + metedata/8 + 8 + 4 + padding/4 = 32
*/
class B2 {
int b2a;
Integer b2b;
}
三、验证
1.
import java.lang.instrument.Instrumentation;
public class ObjectSizeFetcher {
private static Instrumentation instrumentation;
public static void premain(String args, Instrumentation inst) {
instrumentation = inst;
}
public static long getObjectSize(Object o) {
return instrumentation.getObjectSize(o);
}
}
Add the following to your MANIFEST.MF:
Premain-Class: ObjectSizeFetcher
测试对象
public class Cat {
private int x;
private int y;
public static void main(String [] args) {
System.out.println(ObjectSizeFetcher.getObjectSize(new Cat()));
}
}
5.调用
java -javaagent:ObjectSizeFetcherAgent.jar Cat
6.jol-cli-0.8-full.jar 工具
java -jar jol-cli-0.8-full.jar internals java.lang.Long

java -jar jol-cli-0.8-full.jar internals java.util.HashMap

参考:
HotSpotVM 对象机制实现浅析
一个Java对象占用多少字节?
java.lang.instrument: 一个Java对象占用多少字节?的更多相关文章
- [转]new一个Object对象占用多少内存?
我们分解下ArrayList arr = new ArrayList();等同于ArrayList arr = null;//初始化arr = new ArrayList();//实例化这两个过程.初 ...
- J2SE 1.6 特性:java.lang.instrument
1. import java.lang.instrument.Instrumentation; public class ObjectSizeFetcher { private static Inst ...
- java.lang.instrument 中的premain 实现类的个性化加载(附源代码)
背景 想调用ASM API (用于字节码处理的开源API)对字节码进行处理,目标是实现对java程序运行时各种对象的动态跟踪,并进一步分析各个对象之间的关系(研究前提是目前的UML锁阐释的whole- ...
- java.lang.instrument.Instrumentation
java.lang.instrument.Instrumentation 看完文档之后,我们发现这么两个接口:redefineClasses和retransformClasses.一个是重新定义cla ...
- java.lang.instrument使用
Java在1.5引入java.lang.instrument,你可以由此实现一个Javaagent,通过此agent来修改类的字节码即改变一个类. 程序启动之时启动代理(pre-main) 通过jav ...
- java.lang.ClassNotFoundException与java.lang.NoClassDefFoundError的区别
java.lang.ClassNotFoundException与java.lang.NoClassDefFoundError的区别 以前一直没有注意过这个问题,前两天机缘巧合上网查了一下,然后自 ...
- Java源码学习 -- java.lang.StringBuilder,java.lang.StringBuffer,java.lang.AbstractStringBuilder
一直以来,都是看到网上说“ StringBuilder是线程不安全的,但运行效率高:StringBuffer 是线程安全的,但运行效率低”,然后默默记住:一个是线程安全.一个线程不安全,但对内在原因并 ...
- ### Error querying database. Cause: java.lang.IllegalArgumentException: invalid comparison: cn.xiaojian.blog.po.BlogType and java.lang.String ### Cause: java.lang.IllegalArgumentException: ...
### Error querying database. Cause: java.lang.IllegalArgumentException: invalid comparison: cn.xiaoj ...
- java.lang.IndexOutOfBoundsException at java.io.FileOutputStream.writeBytes(Native Method)
ss available : /usr/linkapp/data/linkapp/ddn_1440639847758_temp java.lang.IndexOutOfBoundsException ...
随机推荐
- 李洪强iOS开发之Xcode快捷键
14个Xcode中常用的快捷键操作 在Xcode 6中有许多快捷键的设定可以使得你的编程工作更为高效,对于在代码文件中快速导航.定位Bug以及新增应用特性都是极有效的. 当然,你戳进这篇文章的目的 ...
- windows下控制台程序更改图标和加载资源文件
1.在空项目的Resouce FIles中右击创建一个新的.rc文件. 2.选中这个.rc文件右击在界面中选择导入icon 3.选中icon,将icon的ID更改为IDC_MAINFRAME. 4.重 ...
- eclipse配置代码自动补全auto-completion
你如果使用的是JAVA EE的模式,就这样配置: 1. Window>Preferences>Java>Editor>Content Assist>Auto Activa ...
- Java实现ZIP解压功能
1.引入依赖 <dependency> <groupId>org.apache.ant</groupId> <artifactId>ant</ar ...
- Guardian of Decency UVALive - 3415 最大独立集=结点数-最大匹配数 老师带大学生旅游
/** 题目:Guardian of Decency UVALive - 3415 最大独立集=结点数-最大匹配数 老师带大学生旅游 链接:https://vjudge.net/problem/UVA ...
- centos7.2 安装 Elasticsearch5.2
打算上全文检索,就找到了找个产品,开始研究下…… 1.官网地址: https://www.elastic.co/guide/en/elasticsearch/reference/5.2/install ...
- RTP时间戳
http://xingyunbaijunwei.blog.163.com/blog/static/7653806720126121014111/ ——————————————————————————— ...
- markdown完整语法规范3.0+编辑工具介绍
以下每一种,我都会挑选最常用的一种写法,一切表述只追求简明扼要.想深究,请查看文末链接. 通用写法:符号+空格+内容 1 引用: 单层引用: > 一级引用 多层引用:内层符号前的空格必须要 &g ...
- 第二百一十一节,jQuery EasyUI,ValidateBox(验证框)组件
jQuery EasyUI,ValidateBox(验证框)组件 学习要点: 1.加载方式 2.属性列表 3.方法列表 4.自定义验证 本节课重点了解 EasyUI 中 ValidateBox(验证框 ...
- VC++ 给你的代码强制加一个硬断点
类似与Javascript的 debugger; Hard code a debugger breakpoint If you need to insert a hard breakpoint in ...