计算对象占用内存大小工具类

想明确了解一个对象,比如VO,BO,List占用多少内存空间,可使用此类获得,在评估一些大批量导出时很有用,能够准确评估出一次查询的返回结果list占用多少内存空间

package com;


import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.*;
//一个引用:4字节
//一个Object:8字节
//一个Integer:16字节 == (8 + 4+8-1) / 8 * 8
//一个int:4字节
//长度为0的数组大小:JRo64=24,  Sun32=12


import com.pcm.order.edit.business.model.OrderHeaderBO;


//引用大小,如Object = null:                    JRo64=JRo32=4, Sun32=4, Sun64=8
//无成员的对象大小,如new Object();:     JRo32=JRo64=8, Sun32=8, Sun64=16
//new byte[0]:                        JRo32=JRo64=8+8 Sun32=8+4, Sun64=16+8


//长度l的byte数组:(l+12+8-1)/8*8
//长度l的char/short数组:(l*2+12+8-1)/8*8 == (l+9)/4*8
//长度l的String:(l+1)/4*8+40
//长度l的int数组:(l*4+12+8-1)/8*8 ==(l+4)/2*8
//长度l的long数组:(l*8+12+8-1)/8*8 == (l+2)*8


public class Occupy {
 public static void main(String[] args){
 Occupy oc = new Occupy((byte) 4, (byte) 8, (byte) 4);
 System.out.println(oc.occupyof(new OrderHeaderBO()));
 
 }
 //这8个方法不写不行,否则occupyof(int x)会自动重载到occupyof(Object o),并且无法在方法中判断
 public static int occupyof(boolean variable) {
   return 1;
 }
 
 public static int occupyof(byte variable) {
   return 1;
 }
 
 public static int occupyof(short variable) {
   return 2;
 }
 
 public static int occupyof(char variable) {
   return 2;
 }
 
 public static int occupyof(int variable) {
   return 4;
 }
 
 public static int occupyof(float variable) {
   return 4;
 }
 
 public static int occupyof(long variable) {
   return 8;
 }
 
 public static int occupyof(double variable) {
   return 8;
 }
 
 public Occupy(byte nullReferenceSize, byte emptyObjectSize, byte emptyArrayVarSize) {
   this.NULL_REFERENCE_SIZE = nullReferenceSize;
   this.EMPTY_OBJECT_SIZE = emptyObjectSize;
   this.EMPTY_ARRAY_VAR_SIZE = emptyArrayVarSize;
 }
 
 public static Occupy forJRockitVM() {
   return new Occupy((byte) 4, (byte) 8, (byte) 8);
 }
 
 public static Occupy forSun32BitsVM() {
   return new Occupy((byte) 4, (byte) 8, (byte) 4);
 }
 
 public static Occupy forSun64BitsVM() {
   return new Occupy((byte) 8, (byte) 16, (byte) 8);
 }
 
 public static Occupy forDetectedVM(){
   return null;
 }
 
 private final byte NULL_REFERENCE_SIZE;
 private final byte EMPTY_OBJECT_SIZE;
 private final byte EMPTY_ARRAY_VAR_SIZE;
 
 private static class ref{
   public ref(Object obj){
     this.obj = obj;
   }
   final Object obj;
   @Override
   public boolean equals(Object obj) {
     return (obj instanceof ref) && ((ref)obj).obj == this.obj;
   }
   @Override
   public int hashCode() {
     return obj.hashCode();
   }
 }
 
 private List dedup = new ArrayList();
 
 public int occupyof(Object object){
   dedup.clear();
   return occupyof0(object);
 }
 private int occupyof0(Object object) {
   if (object == null)
     return 0;
   ref r = new ref(object);
   if(dedup.contains(r))
     return 0;
   dedup.add(r);
   int varSize = 0;//对象中的值类型、引用类型变量大小
   int objSize = 0;//对象中的引用类型指向的对象实例的大小
   for (Class clazz = object.getClass(); clazz != Object.class; clazz = clazz.getSuperclass()) {
//      System.out.println(clazz);
     if (clazz.isArray()) {//当前对象的数组
       varSize += EMPTY_ARRAY_VAR_SIZE;
       Class<?> componentType = clazz.getComponentType();
       if (componentType.isPrimitive()) {//当前数组是原生类型的数组
         varSize += lengthOfPrimitiveArray(object) * sizeofPrimitiveClass(componentType);
         return occupyOfSize(EMPTY_OBJECT_SIZE, varSize, 0);
       }
       Object[] array = (Object[]) object;
       varSize += NULL_REFERENCE_SIZE * array.length;//当前数组有length个引用,每个占用4字节
       for (Object o : array)
         objSize += occupyof0(o);
       return occupyOfSize(EMPTY_OBJECT_SIZE, varSize, objSize);
     }
     Field[] fields = clazz.getDeclaredFields();
     for (Field field : fields) {
       if (Modifier.isStatic(field.getModifiers()))
         continue;//类成员不计
       //System.out.println(field.getDeclaringClass());
       if(clazz != field.getDeclaringClass())
         continue;
       Class<?> type = field.getType();
       if (type.isPrimitive())
         varSize += sizeofPrimitiveClass(type);
       else {
         varSize += NULL_REFERENCE_SIZE;//一个引用型变量占用4个字节
         try {
           field.setAccessible(true);//可以访问非public类型的变量
             objSize += occupyof0(field.get(object));
         } catch (Exception e) {
           objSize += occupyofConstructor(object, field);
         }
       }
     }
   }
   return occupyOfSize(EMPTY_OBJECT_SIZE, varSize, objSize);
 }
 
 public static int sizeof(boolean variable) {
   return 1;
 }
 
 public static int sizeof(byte variable) {
   return 1;
 }
 
 public static int sizeof(short variable) {
   return 2;
 }
 
 public static int sizeof(char variable) {
   return 2;
 }
 
 public static int sizeof(int variable) {
   return 4;
 }
 
 public static int sizeof(float variable) {
   return 4;
 }
 
 public static int sizeof(long variable) {
   return 8;
 }
 
 public static int sizeof(double variable) {
   return 8;
 }
 
 
 public int sizeof(Object object) {
   if (object == null)
     return 0;
   int size = EMPTY_OBJECT_SIZE;
   Class clazz = object.getClass();
   if (clazz.isArray()) {
     size += EMPTY_ARRAY_VAR_SIZE;//length变量是int型
     Class<?> componentType = clazz.getComponentType();
     if (componentType.isPrimitive())
       return size + lengthOfPrimitiveArray(object) * sizeofPrimitiveClass(componentType);
     Object[] array = (Object[]) object;
     size += 4 * array.length;
     for (Object o : array)
       size += sizeof(o);
     return size;
   }
   Field[] fields = clazz.getDeclaredFields();
   for (Field field : fields) {
     if (Modifier.isStatic(field.getModifiers()))
       continue;//类成员不计
     Class<?> type = field.getType();
     if (type.isPrimitive())
       size += sizeofPrimitiveClass(type);
     else {
       size += 4;//一个引用型变量占用4个字节
       try {
         field.setAccessible(true);//可以访问非public类型的变量
         size += sizeof(field.get(object));
       } catch (Exception e) {
         size += sizeofConstructor(object, field);
       }
     }
   }
   return size;
 }
 
 private static int occupyofConstructor(Object object, Field field) {
   throw new UnsupportedOperationException("field type Constructor not accessible: " + object.getClass() + " field:" + field);
 }
 
 private static int sizeofConstructor(Object object, Field field) {
   throw new UnsupportedOperationException("field type Constructor not accessible: " + object.getClass() + " field:" + field);
 }
 
 
 private static int occupyOfSize(int size) {
   return (size + 7) / 8 * 8;
 }
 
 private static int occupyOfSize(int selfSize, int varsSize, int objsSize) {
//    System.out.println("self=" + selfSize + " vars=" + varsSize + " objs=" + objsSize);
   return occupyOfSize(selfSize) + occupyOfSize(varsSize) + objsSize;
 }
 
 private static int sizeofPrimitiveClass(Class clazz) {
   return clazz == boolean.class || clazz == byte.class ? 1 : clazz == char.class || clazz == short.class ? 2 : clazz == int.class || clazz == float.class ? 4
       : 8;
 }
 
 private static int lengthOfPrimitiveArray(Object object) {
   Class<?> clazz = object.getClass();
   return clazz == boolean[].class ? ((boolean[]) object).length : clazz == byte[].class ? ((byte[]) object).length
       : clazz == char[].class ? ((char[]) object).length : clazz == short[].class ? ((short[]) object).length
           : clazz == int[].class ? ((int[]) object).length : clazz == float[].class ? ((float[]) object).length
               : clazz == long[].class ? ((long[]) object).length : ((double[]) object).length;
 }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中计算对象内存占用的方式主要有以下几种: 1. 使用Instrumentation API Java提供了一个Instrumentation API,可以通过该API获取对象大小。该API需要在JVM启动时进行注册,具体使用方法如下: ```java 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 obj) { if (instrumentation == null) { throw new IllegalStateException("Instrumentation is null"); } return instrumentation.getObjectSize(obj); } } ``` 在使用该API时,需要在JVM启动时添加如下参数:-javaagent:path/to/agent.jar,其中agent.jar是包含上述代码的jar包。 2. 使用Apache Commons Lang库 Apache Commons Lang库提供了一个SerializationUtils类,可以计算对象大小。具体使用方法如下: ```java import org.apache.commons.lang3.SerializationUtils; public class ObjectSizeFetcher { public static long getObjectSize(Object obj) { byte[] data = SerializationUtils.serialize(obj); return data.length; } } ``` 需要注意的是,该方法需要将对象序列化为字节数组,因此可能会影响性能。 3. 使用自定义工具类 我们也可以自己编写一个工具类计算对象大小。具体实现方法如下: ```java public class ObjectSizeFetcher { private static final Unsafe UNSAFE = getUnsafe(); public static long getObjectSize(Object obj) { if (obj == null) { return 0; } Class<?> clazz = obj.getClass(); if (clazz.isArray()) { int length = Array.getLength(obj); long size = UNSAFE.arrayBaseOffset(clazz) + length * UNSAFE.arrayIndexScale(clazz); return padSize(size); } else { long size = 0; while (clazz != null) { for (Field field : clazz.getDeclaredFields()) { if (!Modifier.isStatic(field.getModifiers())) { size += getSize(field.getType()); } } clazz = clazz.getSuperclass(); } return padSize(size); } } private static long getSize(Class<?> clazz) { if (clazz == boolean.class || clazz == byte.class) { return 1; } else if (clazz == char.class || clazz == short.class) { return 2; } else if (clazz == int.class || clazz == float.class) { return 4; } else if (clazz == long.class || clazz == double.class) { return 8; } else { return getObjectSize(null); } } private static long padSize(long size) { return (size + 7) & ~7; } private static Unsafe getUnsafe() { try { Field field = Unsafe.class.getDeclaredField("theUnsafe"); field.setAccessible(true); return (Unsafe) field.get(null); } catch (Exception e) { throw new RuntimeException(e); } } } ``` 该方法使用了Java的Unsafe类来获取对象内存大小,因此需要注意安全问题。在使用该方法时,需要注意对象内部可能包含引用类型和数组等情况。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值