Unsafe-Java永远的“神”(二)

  • @return

*/

public static Long getAddress(Object obj) {

Object[] objects = new Object[] {obj};

Unsafe unsafe = UnsafeFactory.getUnsafe();

int arrayBaseOffset = unsafe.arrayBaseOffset(Object[].class);

return unsafe.getLong(objects, arrayBaseOffset);

}

/**

  • 获取对象的大小

  • @Dscription

  • Java中实例化一个对象时,JVM会在堆中分配非static的Field的内存,其他的static属性或者method在类加载期间或者JVM启动时已经存放在内存中。

  • 所以我们计算对象的大小的时候只需要求和Field的大小就行了,JVM分配内存时,单个实例对象中的Field内存是连续不断地,

  • 因此我们只需获取最大偏移量Filed的偏移量 + 最大偏移量Filed本身的大小即可

  • Java中基本数据类型所占的字节数

  • byte/boolean 1 字节

  • char/short 2 字节

  • int/float 4 字节

  • long/double 8 字节

  • boolean 理论上占1/8字节,实际上按照1byte处理。

  • Java采用的是Unicode编码,每一个字节占8位,一个字节由8个二进制位组成。

  • @param clazz

  • @return

*/

public static Long size(Class clazz) {

// 最后一个Filed的内存偏移量

long maxOffset = 0;

Class lastFiledClass = null;

Unsafe unsafe = UnsafeFactory.getUnsafe();

do {

for (Field field : clazz.getDeclaredFields()) {

if (!Modifier.isStatic(field.getModifiers())) {

long tmpOffset = unsafe.objectFieldOffset(field);

if (tmpOffset > maxOffset) {

maxOffset = tmpOffset;

lastFiledClass = field.getType();

}

}

}

} while ((clazz = clazz.getSuperclass()) != null);

// 最后一个Field本身的大小

int lastFiledSize = (boolean.class.equals(lastFiledClass) || byte.class.equals(lastFiledClass)) ? 1 :

(short.class.equals(lastFiledClass) || char.class.equals(lastFiledClass)) ? 2 :

(int.class.equals(lastFiledClass) || float.class.equals(lastFiledClass)) ? 4 : 8 ;

return maxOffset + lastFiledSize;

}

/**

  • 申请一块固定大小的内存空间

  • @Description

  • 通过Unsafe的public native long allocateMemory(long var1);申请一块内存空间。

  • @param bytes 需要申请的内存大小

  • @return

*/

public static Long allocateMemory(long bytes) {

return UnsafeFactory.getUnsafe().allocateMemory(bytes);

}

/**

  • 从原对象内存地址srcAddr复制大小位size的内存到destAddr地址处

  • @param srcAddr 源地址

  • @param destAddr 目标地址

  • @param size 复制内存大小

*/

public static void copyMemory(long srcAddr, long destAddr, long size) {

UnsafeFactory.getUnsafe().copyMemory(srcAddr, destAddr, size);

}

/**

  • Unsafe未提供直接读取内存转为Java对象的方法,但是可以通过新建一个包含T类型属性的对象将申请的内存地址赋值给T属性

  • @param addr

  • @param

  • @return

*/

public static T addressConvertObject(long addr) {

Object[] objects = new Object[] {null};

Unsafe unsafe = UnsafeFactory.getUnsafe();

int baseOffset = unsafe.arrayBaseOffset(Object.class);

unsafe.putLong(objects, baseOffset, addr);

return (T)objects[0];

}

/**

  • 实现对象的浅克隆

  • @Description

  • 数组的无法通过此方法实现克隆,数组类是在JVM运行时动态生成的

  • @param t

  • @param

  • @return

*/

public static T shallowClone(T t) {

Class<?> clazz = t.getClass();

if (clazz.isArray()) {

Object[] objects = (Object[]) t;

return (T) Arrays.copyOf(objects, objects.length);

}

Long srcAddr = getAddress(t);

Long size = size(clazz);

Long destAddr = allocateMemory(size);

copyMemory(srcAddr, destAddr, size);

最后

由于篇幅原因,就不多做展示了

92)]

[外链图片转存中…(img-1XzJFo0P-1714479794393)]

[外链图片转存中…(img-YobXQyAb-1714479794393)]

[外链图片转存中…(img-kexVICE6-1714479794393)]

[外链图片转存中…(img-fFhUb2Ln-1714479794394)]

[外链图片转存中…(img-ieVoMhiZ-1714479794394)]

由于篇幅原因,就不多做展示了

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

  • 19
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值