在网上搜到了一篇博客讲的非常好:http://yueyemaitian.iteye.com/blog/2033046。
import java.lang.instrument.Instrumentation;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.HashSet;
import java.util.Set;
/**
* 对象占用字节大小工具类
*
* @author tianmai.fh
* @date 2014-03-18 11:29
*/
public class SizeOfObject {
static Instrumentation inst;
public static void premain(String args, Instrumentation instP) {
inst = instP;
}
/**
* 直接计算当前对象占用空间大小,包括当前类及超类的基本类型实例字段大小、<br></br>
* 引用类型实例字段引用大小、实例基本类型数组总占用空间、实例引用类型数组引用本身占用空间大小;<br></br>
* 但是不包括超类继承下来的和当前类声明的实例引用字段的对象本身的大小、实例引用数组引用的对象本身的大小 <br></br>
*
* @param obj
* @return
*/
public static long sizeOf(Object obj) {
return inst.getObjectSize(obj);
}
/**
* 递归计算当前对象占用空间总大小,包括当前类和超类的实例字段大小以及实例字段引用对象大小
*
* @param objP
* @return
* @throws IllegalAccessException
*/
public static long fullSizeOf(Object objP) throws IllegalAccessException {
Set<Object> visited = new HashSet<Object>();
Deque<Object> toBeQueue = new ArrayDeque<>();
toBeQueue.add(objP);
long size = 0L;
while (toBeQueue.size() > 0) {
Object obj = toBeQueue.poll();
//sizeOf的时候已经计基本类型和引用的长度,包括数组
size += skipObject(visited, obj) ? 0L : sizeOf(obj);
Class<?> tmpObjClass = obj.getClass();
if (tmpObjClass.isArray()) {
//[I , [F 基本类型名字长度是2
if (tmpObjClass.getName().length() > 2) {
for (int i = 0, len = Array.getLength(obj); i < len; i++) {
Object tmp = Array.get(obj, i);
if (tmp != null) {
//非基本类型需要深度遍历其对象
toBeQueue.add(Array.get(obj, i));
}
}
}
} else {
while (tmpObjClass != null) {
Field[] fields = tmpObjClass.getDeclaredFields();
for (Field field : fields) {
if (Modifier.isStatic(field.getModifiers()) //静态不计
|| field.getType().isPrimitive()) { //基本类型不重复计
continue;
}
field.setAccessible(true);
Object fieldValue = field.get(obj);
if (fieldValue == null) {
continue;
}
toBeQueue.add(fieldValue);
}
tmpObjClass = tmpObjClass.getSuperclass();
}
}
}
return size;
}
/**
* String.intern的对象不计;计算过的不计,也避免死循环
*
* @param visited
* @param obj
* @return
*/
static boolean skipObject(Set<Object> visited, Object obj) {
if (obj instanceof String && obj == ((String) obj).intern()) {
return true;
}
return visited.contains(obj);
}
}
对其进行了验证,产生一些疑惑。例如原本确定计算String 对象占用的对象大小为
<64位机> 2*N + 64 + padding
<32位机> 2*N + 40 + padding
N为字符串长度,但使用
String s1 = "111";
System.out.println(SizeOfObject.fullSizeOf(s1));
得到的大小只有24个字节(我的机器为32位),正常的大小为48个字节少了24字节,原因是什么呢?
问题出在skipObject,此时"111"为String.intern的对象即存在常量池中,
对于 String(JDK 6)的成员变量声明如下:
private final char value[];
private final int offset;
private final int count;
private int hash;
那么就会少<32位机>8(对象开销) + 12字节(3个int) + 4(char[]引用) =24字节的开销,只计算value[] 占用的内存大小,16+3*2+padding = 24。对于整个JVM,常量池可以共享,所以不计算也不会有太大的偏差。
在代码中还有个bug,visited中在整个过程中并没有起到什么作用。
分享到:
相关推荐
在Java编程语言中,了解一个对象占用的内存字节数对于优化内存使用和理解程序性能至关重要。本篇文章将深入探讨如何计算Java对象占用的内存字节数,以及影响这一数值的因素。 首先,Java对象在堆内存中由四个部分...
实验显示`Person`对象占用40字节,这是因为对象头的Klass Pointer从4字节增长到8字节,其他部分保持不变,总大小增加了8字节。 3. 数组的内存存储布局: 数组的内存占用除了包含对象头之外,还包括数组长度(4字节...
实例变量的大小取决于它们的数据类型,例如,一个int占4字节,一个double占8字节,一个引用占32位JVM的4字节或64位JVM的8字节。需要注意的是,基本类型的大小是固定的,但引用的大小会因是否开启压缩引用而变化。 3...
每种原始类型都对应着一个包装类(Wrapper Class),包装类是原始类型的对象表示形式。包装类提供了许多有用的方法,可以对原始类型进行操作。 在 Java 中,原始类型可以分为两大类:整数类型和浮点数类型。整数...
在Java编程语言中,了解一个对象的内存大小是很有用的,特别是在性能调优和内存管理方面。`sizeOf`通常是指用来计算对象在内存中占用空间的一种方法。本篇文章将探讨如何通过Java来实现这样的功能,以及相关知识点。...
这段代码首先创建了一个空的字节集,然后将一个字符串转换为字节集并赋值,最后调用“清空”命令清空字节集。这样,字节集就回到了无数据的状态。 清空字节集的效率对于处理大量数据的程序至关重要。易语言在设计时...
如果父类的最后一个属性与子类的第一个属性之间有不足4字节的空隙,会进行填充以满足4字节对齐。例如: ```java class A { byte a; } class B extends A { byte b; } ``` 这时,大小将是: - 头部(8字节) - ...
在Java编程语言中,了解一个对象占用的内存大小是非常重要的,尤其是在优化性能或者处理大量对象时。本示例主要探讨如何测试Java对象占用的内存大小,以便更好地理解内存使用情况。 首先,`SizeOf.java`可能是一个...
在Java编程语言中,了解一个对象占用的内存大小对于优化程序性能、理解内存消耗以及防止内存泄漏至关重要。本文将深入探讨如何计算Java对象所占内存,并通过提供的代码示例进行详细解析。 首先,我们需要理解Java...
"计算对象占用内存空间ObjectSize-master.zip" 提供的工具可能是一个帮助开发者分析和估算对象在内存中占用大小的解决方案。这样的工具对于调试、性能调优以及避免内存泄漏至关重要。 在Java中,对象的内存占用不...
- `MOV 07H, #07H`:这也是三字节指令,`MOV`占用一个字节,8位地址`07H`占用一个字节,8位立即数`#07H`占用一个字节。 此外,提到的BCD码减数求补问题是一个典型的应用示例。在51单片机中,由于`DA A`指令只能用于...
4. **创建字节集**:使用“创建字节集”命令创建一个新的字节集,并将编码后的数据填充进去。 5. **保存字节集**:将字节集写入文件,可以使用“写入文件全部字节”命令。 四、易语言中的相关函数 - **读取文件...
- "字节码+压缩存" 可能是一个实现将字节码形式的对象进行压缩并存储到 Redis 的类或方法。 - "字节码转字符存" 可能是将字节码解压后转化为字符形式(例如JSON或XML),以便于阅读和调试的工具。 总结,Redis 在...
在ASCII编码中,每个字符对应一个字节,但在Unicode编码(包括UTF-8)中,不同字符可能占用不同的字节数。UTF-8是最常用的Unicode变体,它根据字符的复杂性占用1至4个字节。 下面是一种基于UTF-8的JavaScript函数,...
查看当前数据库中每个表所占字节(空间)大小
在Java编程环境中,了解对象占用的内存大小是优化性能的关键步骤。这可以帮助我们避免内存泄漏,提高应用程序的效率。本文将深入探讨如何统计缓存(尤其是Java对象)所占的内存大小,以及这对理解程序内存消耗的重要...
在易语言中,字节集可以被看作一个数组,数组的每个元素都是一个字节。当需要将图片保存到文件或者在网络上传输时,通常会将图片转换成字节集形式。 在易语言图片句柄取图片字节集的操作中,主要是将内存中的图片...
在易语言中,字节集是一个重要的数据类型,用来存储二进制数据,例如图片、音频文件或者网络传输的数据。字节集的格式转换是编程过程中常见的一种操作,涉及到不同类型数据之间的互换。 字节集的格式转换通常包括两...
在E4A中,我们可以使用`ByteSet()`函数来创建一个空的字节集,或者使用`CopyToByteSet()`方法从其他数据结构复制数据。 3. **字节集操作**: - **添加/删除字节**:通过`AddByte()`和`RemoveByte()`方法,可以向...
一个空的String对象占用28个字节的内存,包含了一个指向字符数组的引用、一个偏移量、一个字符的长度和一个哈希码。当字符串内容非空时,内存占用会增加,因为需要存储字符数据。例如,字符串"ab"会占用28 + 2 * 2 =...