http接口返回一堆数据,从数据库内查询出一堆数据,程序接收,并封装成对象。那么问题来了,这些对象在内存内占多少空间?
有时候看一个http接口返回5M的数据就觉的吓人,总有一种调用次数多了服务器要爆了的感觉。当然这是开玩笑的,服务器怎么会爆,充其量宕机。
之前一直不知道怎么计算对象在内存上的大小。其实是思维太死,一个java对象,说到底就是由field与method组成的。method我先不管,field,这个就很好理解了,基础类型,包装类型,或者类类型。不过真的仔细追踪下去,其实不管什么类类型,到头来都是由基础类型组成的,君不见数据库也就存存数字、字符串…… ……
因此,以model类为例,这玩意就像一个套娃,不停的把基础类型包来包去。
而基础类型有多大,这是有规定的:
| boolean类型 | 占 1 bit |
| byte类型 | 占8bit(1字节) |
| char类型 | 占16 bit(2字节) |
| short类型 | 占16 bit(2字节) |
| int类型 | 占32bit(4字节) |
| long类型 | 占64bit(8字节) |
| float | 占32bit(4字节) |
| double类型 | 占64bit(8字节) |
所以理论上讲,通过递归加反射是可以计算对象在内存中的占多少字节的。
下面是一个demo,可以做简单计算,但是碰到包含集合之类的对象的怕是不行,感兴趣的朋友可以一起实现:
public class ObjectMemorySizeUtil {
/**
* 获取某对象在内存中占用的bit数
*
* @param object
* @return
* @throws IllegalAccessException
*/
public static final int getObjectMemorySize(Object object) throws IllegalAccessException {
if (object == null || object instanceof Class<?>) {
return 0;
}
Class<?> objectClass = object.getClass();
if (isPrimitive(objectClass)) {
return getPrimitiveMemorySize(objectClass);
}
if (objectClass.isArray()) {
return getArrayMemorySize(object);
}
Field[] fieldArr = objectClass.getDeclaredFields();
if (ArrayUtils.isEmpty(fieldArr)) {
return 0;
}
int result = 0;
for (Field field : fieldArr) {
field.setAccessible(true);
result += getObjectMemorySize(field.get(object));
}
return result;
}
/**
* 获取数据类型占用bit数
*
* @param object
* @return
* @throws IllegalAccessException
*/
private static int getArrayMemorySize(Object object) throws IllegalAccessException {
int length = Array.getLength(object);
if (length == 0) {
return 0;
}
int result = 0;
for (int i = 0; i < length; i++) {
Object obj = Array.get(object, i);
result += getObjectMemorySize(obj);
}
return result;
}
/**
* 是否原生类型
*
* @param objectClass
* @return
*/
private static boolean isPrimitive(Class<?> objectClass) {
String classSimpleName = objectClass.getSimpleName();
String[] wrapperClassArr = {"Boolean", "Byte", "Character", "Short", "Integer", "Long", "Float", "Double"};
return objectClass.isPrimitive() || StringUtils.equalsAny(classSimpleName, wrapperClassArr);
}
/**
* 获取原生类型占用bit数
*
* @param objectClass
* @return
*/
private static int getPrimitiveMemorySize(Class<?> objectClass) {
String classSimpleName = objectClass.getSimpleName();
if (StringUtils.equalsIgnoreCase(classSimpleName, "boolean")) {
return 1;
} else if (StringUtils.equalsIgnoreCase(classSimpleName, "byte")) {
return 8;
} else if (StringUtils.equalsAny(classSimpleName, "Character", "char")) {
return 16;
} else if (StringUtils.equalsIgnoreCase(classSimpleName, "short")) {
return 16;
} else if (StringUtils.equalsAny(classSimpleName, "Integer", "int")) {
return 32;
} else if (StringUtils.equalsIgnoreCase(classSimpleName, "long")) {
return 64;
} else if (StringUtils.equalsIgnoreCase(classSimpleName, "float")) {
return 32;
} else if (StringUtils.equalsIgnoreCase(classSimpleName, "double")) {
return 64;
}
return 0;
}
public static void main(String[] args) throws IllegalAccessException {
ObjectMemorySizeUtil obj = new ObjectMemorySizeUtil();
System.out.println(getObjectMemorySize(obj));
}
private int a;
private char b;
private int[] cArr = new int[4];
}