上一篇文章中。我们列出了计算java对象大小的几个结论以及jol工具的使用,jol工具的源代码有兴趣的能够去看下。如今我们利用JDK中的sun.misc.Unsafe来计算下字段的偏移地址,一则验证下之前文章中的结论,再则跟jol输出结果对照下。怎样获取sun.misc.Unsafe对象。能够參考这篇文章

  1. public class VO
  2. {
  3. public int a = 0;
  4.  
  5. public long b = 0;
  6.  
  7. public static String c= "123";
  8.  
  9. public static Object d= null;
  10.  
  11. public static int e = 100;
  12. }

1.获取实例字段的偏移地址

  1. // 获取实例字段的偏移地址,偏移最小的那个字段(仅挨着头部)就是对象头的大小
  2. System.out.println(unsafe.objectFieldOffset(VO.class.getDeclaredField("a")));
  3. System.out.println(unsafe.objectFieldOffset(VO.class.getDeclaredField("b")));
  4.  
  5. // fieldOffset与objectFieldOffset功能一样,fieldOffset是过时方法,最好不要再使用
  6. System.out.println(unsafe.fieldOffset(VO.class.getDeclaredField("b")));

2.获取数组的头部大小和元素大小

  1. // 数组第一个元素的偏移地址,即数组头占用的字节数
  2. int[] intarr = new int[0];
  3. System.out.println(unsafe.arrayBaseOffset(intarr.getClass()));
  4.  
  5. // 数组中每一个元素占用的大小
  6. 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.获取类的静态字段偏移

  1. // 获取类的静态字段偏地址
  2. System.out.println(unsafe.staticFieldOffset(VO.class.getDeclaredField("c")));
  3. System.out.println(unsafe.staticFieldOffset(VO.class.getDeclaredField("d")));
  4.  
  5. // 获取静态字段的起始地址,通过起始地址和偏移地址,就能够获取静态字段的值了
  6. // 仅仅只是静态字段的起始地址,类型不是long,而是Object类型
  7. Object base1 = unsafe.staticFieldBase(VO.class);
  8. Object base2 = unsafe.staticFieldBase(VO.class.getDeclaredField("d"));
  9. System.out.println(base1==base2);//true

4.获取操作系统的位数

  1. // Report the size in bytes of a native pointer.
  2. // 返回4或8,代表是32位还是64位操作系统。
  3. System.out.println(unsafe.addressSize());
  4. // 返回32或64,获取操作系统是32位还是64位
  5. System.out.println(System.getProperty("sun.arch.data.model"));

通过上面的几段代码。我们可以成功获取类中各个字段的偏移地址,这跟jol工具的输出结果和我们的结论是一致的。

有了字段的偏移地址,在加上对象的起始地。我们就行通过Unsafe直接获取字段的值了。

5.读取对象实例字段的值

  1. //获取实例字段的属性值
  2. VO vo = new VO();
  3. vo.a = 10000;
  4. long aoffset = unsafe.objectFieldOffset(VO.class.getDeclaredField("a"));
  5. int va = unsafe.getInt(vo, aoffset);
  6. System.out.println("va="+va);

6.获取静态字段的属性值

  1. VO.e = 1024;
  2. Field sField = VO.class.getDeclaredField("e");
  3. Object base = unsafe.staticFieldBase(sField);
  4. long offset = unsafe.staticFieldOffset(sField);
  5. System.out.println(unsafe.getInt(base, offset));//1024

能够看到Unsafe功能是非常强大的,位java语言提供了更底层的功能。

java对象的内存布局(二):利用sun.misc.Unsafe获取类字段的偏移地址和读取字段的值的更多相关文章

  1. Java对象的内存布局以及对象的访问定位

    一 Java对象的内存布局 在HotSpot虚拟机中,对象在内存中的布局分为3个区域 对象头(Header) Mark Word(在32bit和64bit虚拟机上长度分别为32bit和64bit)存储 ...

  2. 3 Java对象的内存布局以及对象的访问定位

    先来看看Java对象在内存中的布局   一 Java对象的内存布局 在HotSpot虚拟机中,对象在内存中的布局分为3个区域 对象头(Header) Mark Word(在32bit和64bit虚拟机 ...

  3. Java对象的内存布局

    对象的内存布局 平时用java编写程序,你了解java对象的内存布局么? 在HotSpot虚拟机中,对象在内存中存储的布局可以分为3块区域: 对象头 实例数据 对齐填充 对象头 对象头包括两部分信息: ...

  4. java.util.concurrent各组件分析 一 sun.misc.Unsafe

    java.util.concurrent各组件分析 一 sun.misc.Unsafe 说到concurrent包也叫并发包,该包下主要是线程操作,方便的进行并发编程,提到并发那么锁自然是不可缺少的, ...

  5. JVM总结-java对象的内存布局

    在 Java 程序中,我们拥有多种新建对象的方式.除了最为常见的 new 语句之外,我们还可以通过反射机制.Object.clone 方法.反序列化以及 Unsafe.allocateInstance ...

  6. Java对象的内存布局以及对象所需内存大小计算详解

    1. 内存布局 在HotSpot虚拟机中,对象的内存布局可以分为三部分:对象头(Header). 实例数据(Instance Data)和对齐填充(Padding). 1) 对象头(Header): ...

  7. 10 Java 对象的内存布局

    Java 创建对象的方式 1:new 语句和反射机制创建.该方式会调用类的构造器,同时满足诸多约束.如果一个类没有构造器的话,Java 编译器会自动添加一个无参数的构造器.子类的构造器需要调用父类的构 ...

  8. 一个Java对象的内存布局

    1.对象的创建过程 class loading class linking(verification,preparation,resolution) class initializing 申请对象内存 ...

  9. 深入理解 Java 对象的内存布局

    对于 Java 虚拟机,我们都知道其内存区域划分成:堆.方法区.虚拟机栈等区域.但一个对象在 Java 虚拟机中是怎样存储的,相信很少人会比较清楚地了解.Java 对象在 JVM 中的内存布局,是我们 ...

随机推荐

  1. 纯CSS美化的checkbox 和 radio

    html <!DOCTYPE HTML> <html> <head> <title>纯CSS3实现自定义美化复选框和单选框</title> ...

  2. hdu 2665 Kth number_划分树

    题意:求区间[a,b]的第k大 因为多次询问要用到划分树 #include <iostream> #include<cstdio> #include<algorithm& ...

  3. 蜂窝移动网络是什么,它和 Wi-Fi 有什么区别? 蓝牙和无线有什么区别?

    蜂窝移动网络是什么,它和 Wi-Fi 有什么区别? 转自知乎用户的一个回答: 原题问的是"数据流量是什么",不知道怎么又被改成"蜂窝移动网络是什么"了.说下个人 ...

  4. hdu 4393 Throw nails(STL之优先队列)

    Problem Description The annual school bicycle contest started. ZL is a student in this school. He is ...

  5. 浅析WebGIS

    浅析WebGIS 摘要:随着网络的发展,利用Web公布信息越来越普及化.而地理信息系统(GIS)与网络的结合就产生了万维网地理信息系统(WebGIS),它引起了地理信息公布的新的变革,对实现GIS信息 ...

  6. OA 权限控制

    对于加入删除 初始化password等操作的权限 控制 第一种方法就是在每一个超链接前加 推断 如 <s:if test="#session.user.hasPrivilegeByNa ...

  7. 彩虹vpn免费10分钟

    账号:rainbowvpn password:10fenzhong server地址:t.chqvpn.com l2tp密钥:123456

  8. 好用的DNS服务器推荐

    DNS在平时上网中扮演重要角色,如果不注意DNS的话,可能会导致网速慢.弹窗广告.网址打不开.打开不是自己想要的网站.淘宝客劫持等一系列问题.针对DNS的问题,网络上也有各种DNS平台供用户选择.这里 ...

  9. 依赖注入及AOP简述(五)——依赖注入的方式 .

    二.依赖注入的应用模式 前面我们了解了依赖注入的基本概念,也对一些依赖注入框架进行了简单的介绍,这一章我们主要来讨论作为开发者如何利用依赖注入框架来实现依赖注入的设计思想. 1.     依赖注入的方 ...

  10. Oracle使用imp/exop远程导入导出dmp数据

    在导入导出数据之前,习惯性的检查一下,看看我们自己的机器可不可以连接远程的Oracle主机,检测方法是tnsping SERVICE_NAME.我的机器如下: C:\Users\zx>tnspi ...