java对象的内存布局(二):利用sun.misc.Unsafe获取类字段的偏移地址和读取字段的值
在上一篇文章中。我们列出了计算java对象大小的几个结论以及jol工具的使用,jol工具的源代码有兴趣的能够去看下。如今我们利用JDK中的sun.misc.Unsafe来计算下字段的偏移地址,一则验证下之前文章中的结论,再则跟jol输出结果对照下。怎样获取sun.misc.Unsafe对象。能够參考这篇文章。
public class VO
{
public int a = 0; public long b = 0; public static String c= "123"; public static Object d= null; public static int e = 100;
}
1.获取实例字段的偏移地址
// 获取实例字段的偏移地址,偏移最小的那个字段(仅挨着头部)就是对象头的大小
System.out.println(unsafe.objectFieldOffset(VO.class.getDeclaredField("a")));
System.out.println(unsafe.objectFieldOffset(VO.class.getDeclaredField("b"))); // fieldOffset与objectFieldOffset功能一样,fieldOffset是过时方法,最好不要再使用
System.out.println(unsafe.fieldOffset(VO.class.getDeclaredField("b")));
2.获取数组的头部大小和元素大小
// 数组第一个元素的偏移地址,即数组头占用的字节数
int[] intarr = new int[0];
System.out.println(unsafe.arrayBaseOffset(intarr.getClass())); // 数组中每一个元素占用的大小
System.out.println(unsafe.arrayIndexScale(intarr.getClass()));
Unsafe类中有非常多以BASE_OFFSET结尾的常量,比方ARRAY_INT_BASE_OFFSET等,这些常量值是通过arrayBaseOffset方法得到的。arrayBaseOffset方法是一个本地方法,能够获取数组第一个元素的偏移地址。Unsafe类中还有非常多以INDEX_SCALE结尾的常量,比方 ARRAY_INT_INDEX_SCALE 等。这些常量值是通过arrayIndexScale方法得到的。将arrayBaseOffset与arrayIndexScale配合使用,能够定位数组中每一个元素在内存中的位置。
3.获取类的静态字段偏移
// 获取类的静态字段偏地址
System.out.println(unsafe.staticFieldOffset(VO.class.getDeclaredField("c")));
System.out.println(unsafe.staticFieldOffset(VO.class.getDeclaredField("d"))); // 获取静态字段的起始地址,通过起始地址和偏移地址,就能够获取静态字段的值了
// 仅仅只是静态字段的起始地址,类型不是long,而是Object类型
Object base1 = unsafe.staticFieldBase(VO.class);
Object base2 = unsafe.staticFieldBase(VO.class.getDeclaredField("d"));
System.out.println(base1==base2);//true
4.获取操作系统的位数
// Report the size in bytes of a native pointer.
// 返回4或8,代表是32位还是64位操作系统。
System.out.println(unsafe.addressSize());
// 返回32或64,获取操作系统是32位还是64位
System.out.println(System.getProperty("sun.arch.data.model"));
通过上面的几段代码。我们可以成功获取类中各个字段的偏移地址,这跟jol工具的输出结果和我们的结论是一致的。
有了字段的偏移地址,在加上对象的起始地。我们就行通过Unsafe直接获取字段的值了。
5.读取对象实例字段的值
//获取实例字段的属性值
VO vo = new VO();
vo.a = 10000;
long aoffset = unsafe.objectFieldOffset(VO.class.getDeclaredField("a"));
int va = unsafe.getInt(vo, aoffset);
System.out.println("va="+va);
6.获取静态字段的属性值
VO.e = 1024;
Field sField = VO.class.getDeclaredField("e");
Object base = unsafe.staticFieldBase(sField);
long offset = unsafe.staticFieldOffset(sField);
System.out.println(unsafe.getInt(base, offset));//1024
能够看到Unsafe功能是非常强大的,位java语言提供了更底层的功能。
java对象的内存布局(二):利用sun.misc.Unsafe获取类字段的偏移地址和读取字段的值的更多相关文章
- Java对象的内存布局以及对象的访问定位
一 Java对象的内存布局 在HotSpot虚拟机中,对象在内存中的布局分为3个区域 对象头(Header) Mark Word(在32bit和64bit虚拟机上长度分别为32bit和64bit)存储 ...
- 3 Java对象的内存布局以及对象的访问定位
先来看看Java对象在内存中的布局 一 Java对象的内存布局 在HotSpot虚拟机中,对象在内存中的布局分为3个区域 对象头(Header) Mark Word(在32bit和64bit虚拟机 ...
- Java对象的内存布局
对象的内存布局 平时用java编写程序,你了解java对象的内存布局么? 在HotSpot虚拟机中,对象在内存中存储的布局可以分为3块区域: 对象头 实例数据 对齐填充 对象头 对象头包括两部分信息: ...
- java.util.concurrent各组件分析 一 sun.misc.Unsafe
java.util.concurrent各组件分析 一 sun.misc.Unsafe 说到concurrent包也叫并发包,该包下主要是线程操作,方便的进行并发编程,提到并发那么锁自然是不可缺少的, ...
- JVM总结-java对象的内存布局
在 Java 程序中,我们拥有多种新建对象的方式.除了最为常见的 new 语句之外,我们还可以通过反射机制.Object.clone 方法.反序列化以及 Unsafe.allocateInstance ...
- Java对象的内存布局以及对象所需内存大小计算详解
1. 内存布局 在HotSpot虚拟机中,对象的内存布局可以分为三部分:对象头(Header). 实例数据(Instance Data)和对齐填充(Padding). 1) 对象头(Header): ...
- 10 Java 对象的内存布局
Java 创建对象的方式 1:new 语句和反射机制创建.该方式会调用类的构造器,同时满足诸多约束.如果一个类没有构造器的话,Java 编译器会自动添加一个无参数的构造器.子类的构造器需要调用父类的构 ...
- 一个Java对象的内存布局
1.对象的创建过程 class loading class linking(verification,preparation,resolution) class initializing 申请对象内存 ...
- 深入理解 Java 对象的内存布局
对于 Java 虚拟机,我们都知道其内存区域划分成:堆.方法区.虚拟机栈等区域.但一个对象在 Java 虚拟机中是怎样存储的,相信很少人会比较清楚地了解.Java 对象在 JVM 中的内存布局,是我们 ...
随机推荐
- JDBC批量操作
/** * 批量执行预定义模式的SQL */ public static void exeBatchParparedSQL() { ...
- uva 10041 Vito's Family_贪心
题意:给你n个房子的距离,问那个房子离别的房子的距离最近,并且输出与别的房子距离的总和 思路:排序一下,中间的房子离别房子距离必然是最少的. #include <iostream> #in ...
- SQL_SERVER日期函数详细用法
1.一个月第一天的 Select DATEADD(mm, DATEDIFF(mm,0,getdate()), 0) 2.本周的星期一 Select DATEADD(wk, DATEDIFF(wk,0, ...
- 百度地图 Android SDK - Hello Baidu Map
例如,给广大以下主要开发者介绍了如何使用百度地图Android SDK构造的主应用程序的地图! 第一步.创建Androidproject,将百度地图Android SDK的开发包导入到project对 ...
- Devexpress之barManager控件属性
隐藏菜单栏左边的竖线和右边的箭头? 1.隐藏菜单栏上右边的箭头属性设置:OptionsBar=>>AllowQuickCustomization=False 2.隐藏菜单栏左边的竖线属性设 ...
- JDK8环境变量配置相关问题
1.右键选择 计算机→属性→高级系统设置→高级→环境变量 2.系统变量→新建 变量名:JAVA_HOME 变量值:(变量值填写你的jdk的安装目录,例如本人是 E:Javajdk1.7.0) 3.在系 ...
- 消息机制JMS
消息机制JMS http://wenku.baidu.com/link?url=5FiNu_HP3lUFKhePmfCUPE09DV_f9-tsQ4NpWtKxHYphxAglzsjg3XSM8Sz6 ...
- C++ vector 实现二维数组时, 在类的头文件中定义时遇到"应输入类型符"的问题?
见下,当我在类的声明文件中定义二维vector时,提示我应输入类型说明符; 但是相同的格式定义,在类中将二维vector修改为在源文件中定义就可以顺利通过,并顺利执行打印 打印结果如下: 望大神来解惑 ...
- 在Linux上使用cmake创建CodeBlocks工程
最近在linux上使用cmake,对于使用GUI习惯的还真不能适应,真是想尽一切办法把原来使用cmake的工程创建成CodeBlocks工程.工程小了还能接受,工程大了太麻烦了. 看了一下cmake的 ...
- mysql 存在该记录则更新,不存在则插入记录的sql
转 http://www.cnblogs.com/zeroone/articles/2298929.html , ‘yourname') ON DUPLICATE KEY UPDATE auto_na ...