J2SE 1.6 特性:java.lang.instrument
一、对象头包括两部分信息: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对象占用多少字节?
J2SE 1.6 特性:java.lang.instrument的更多相关文章
- java.lang.instrument使用
Java在1.5引入java.lang.instrument,你可以由此实现一个Javaagent,通过此agent来修改类的字节码即改变一个类. 程序启动之时启动代理(pre-main) 通过jav ...
- java.lang.instrument 中的premain 实现类的个性化加载(附源代码)
背景 想调用ASM API (用于字节码处理的开源API)对字节码进行处理,目标是实现对java程序运行时各种对象的动态跟踪,并进一步分析各个对象之间的关系(研究前提是目前的UML锁阐释的whole- ...
- java.lang.instrument: 一个Java对象占用多少字节?
一.对象头包括两部分信息:Mark Word(标记字段)和 Klass Pointer(类型指针) 1. Mark Word 用于存储对象自身的运行时数据,如哈希码(HashCode).GC分代年 ...
- java.lang.instrument.Instrumentation
java.lang.instrument.Instrumentation 看完文档之后,我们发现这么两个接口:redefineClasses和retransformClasses.一个是重新定义cla ...
- java.lang包
作者:gnuhpc 出处:http://www.cnblogs.com/gnuhpc/ 1.特性——不用import 2.String String x = "abc"; < ...
- 浅析Java.lang.ProcessBuilder类
最近由于工作需要把用户配置的Hive命令在Linux环境下执行,专门做了一个用户管理界面特地研究了这个不经常用得ProcessBuilder类.所以把自己的学习的资料总结一下. 一.概述 P ...
- jdk研究——java.lang
jdk研究 volatile 是什么意思? 如何看jdk源码? 如何调试源码!---------仔细解读关键类,关键代码,常用的api的解释! 自己有疑问的不懂地方-------- 不懂的太多怎么办. ...
- 深入研究java.lang.ProcessBuilder类
深入研究java.lang.ProcessBuilder类 一.概述 ProcessBuilder类是J2SE 1.5在java.lang中新添加的一个新类,此类用于创建操作系统进程,它 ...
- [转载]使用java.lang.Process类的简单例子
FROM: http://segmentfault.com/blog/lidonghao/1190000000372192 ProcessBuilder类是J2SE 1.5在java.lang中新添加 ...
随机推荐
- .NET中异常处理的最佳实践(转)
原文出处: CodeProject 译文出处:周见智的博客 欢迎分享原创到伯乐头条 介绍 “我的软件程序从来都不会出错”.你们相信吗?我几乎可以肯定所有人都会大喊我是个骗子.“软件程序几乎不可 ...
- node工具--express
//使用supervisor Connect是基于HTTP米快创建的:Express则是基于Connect上创建的: 绝大多数web服务器和浏览器之间的任务是通过url和method完成的,两者的组 ...
- 解决eclipse中git插件中的cannot open git-upload-pack问题
有时候在eclipse上使用插件egit向github或者osc上同步代码时,有时候会发现出现cannot open git-upload-pack这个问题. 一般引起这个问题的原因有两个:一.网络问 ...
- oracle 11g安装(转)
原文地址:http://www.2cto.com/database/201208/150620.html 一.Oracle 下载 注意Oracle分成两个文件,下载完后,将两个文件解压到同一目录下即可 ...
- 状态压缩 UVALive 6068 The Little Girl who Picks Mushrooms (12长春C)
题目传送门 题意:采蘑菇.现在采了n座山,共5座山,最后要求有三个篮子的蘑菇量是1024的整数倍,丢掉后一直减1024直到不超过1024 分析:n <= 3时直接1024,否则状压枚举哪三个篮子 ...
- Converting Stream to String and back…what are we missing?
string test = "Testing 1-2-3"; // convert string to stream byte[] byteArray = Encoding.ASC ...
- BZOJ3838 : [Pa2013]Raper
将选取的$A$看成左括号,$B$看成右括号,那么答案是一个合法的括号序列. 那么只要重复取出$k$对价值最小的左右括号,保证每时每刻都是一个合法的括号序列即可. 将$($看成$1$,$)$看成$-1$ ...
- storm源码之一个class解决nimbus单点问题【转】
本文导读: storm nimbus 单节点问题概述 storm与解决nimbus单点相关的概念 nimbus目前无法做到多节点的原因 解决nimbus单点问题的关键 业界对nimbus单点问题的努力 ...
- [Cocos2d-x For WP8]MotionStreak拖尾效果
拖尾效果是指在在游戏中,一个精灵在运动的过程中会留下一个短暂的轨迹效果,在游戏里面如打斗的特效往往会需要用到这种效果来给运动的增加绚丽的效果.那么在Cocos2D-x里面我们可以使用一种内置的拖动渐隐 ...
- 【BZOJ】1084: [SCOI2005]最大子矩阵(DP)
http://www.lydsy.com/JudgeOnline/problem.php?id=1084 有一个1A--- 本题没看懂,,不会啊囧..感觉完全设不了状态..看了题解,囧,m<=2 ...