我想知道检索java对象大小的任何简单方法吗?另外,无论如何要在c ++中获得像sizeof运算符这样的类的大小?
答案 0 :(得分:16)
有opensource java.SizeOf project确定内存中任何Java对象的大小。
答案 1 :(得分:6)
Instrumentation接口有一个getObjectSize()方法。
但是这只会给出对象本身的大小,而不是它的组件子对象。例如,它会告诉您所有String
个对象的大小都相同。
另一个问题是物体的大小实际上可以自发地改变。例如,如果您获得对象的标识哈希码并且它在GC周期中存活,那么它的大小将增加(至少)4个字节以存储标识哈希码值。
找到“对象”的大小的问题在于,通用实用程序类/方法不可能确定任意对象的抽象边界在哪里。有一些问题甚至像String类一样简单。 (考虑在Java 6中使用substring(...)
创建的String对象。您可以将char[] value
对象作为this
的一部分,还是原始String的一部分,或两者兼而有之?这对于什么意味着什么?各个对象的大小?)
因此,像net.sourceforge.sizeof
这样的东西不可能完全准确地说明空间使用情况。
答案 2 :(得分:3)
使用Unsafe
中的sun.misc
类,您可以获得字段偏移量。因此,根据处理器体系结构考虑对象堆对齐并计算最大字段偏移量,您可以测量Java对象的大小。在下面的示例中,我使用辅助类UtilUnsafe
来获取对sun.misc.Unsafe
对象的引用。
private static final int NR_BITS = Integer.valueOf(System.getProperty("sun.arch.data.model"));
private static final int BYTE = 8;
private static final int WORD = NR_BITS/BYTE;
private static final int MIN_SIZE = 16;
public static int sizeOf(Class src){
//
// Get the instance fields of src class
//
List<Field> instanceFields = new LinkedList<Field>();
do{
if(src == Object.class) return MIN_SIZE;
for (Field f : src.getDeclaredFields()) {
if((f.getModifiers() & Modifier.STATIC) == 0){
instanceFields.add(f);
}
}
src = src.getSuperclass();
}while(instanceFields.isEmpty());
//
// Get the field with the maximum offset
//
long maxOffset = 0;
for (Field f : instanceFields) {
long offset = UtilUnsafe.UNSAFE.objectFieldOffset(f);
if(offset > maxOffset) maxOffset = offset;
}
return (((int)maxOffset/WORD) + 1)*WORD;
}
class UtilUnsafe {
public static final sun.misc.Unsafe UNSAFE;
static {
Object theUnsafe = null;
Exception exception = null;
try {
Class<?> uc = Class.forName("sun.misc.Unsafe");
Field f = uc.getDeclaredField("theUnsafe");
f.setAccessible(true);
theUnsafe = f.get(uc);
} catch (Exception e) { exception = e; }
UNSAFE = (sun.misc.Unsafe) theUnsafe;
if (UNSAFE == null) throw new Error("Could not obtain access to sun.misc.Unsafe", exception);
}
private UtilUnsafe() { }
}
答案 3 :(得分:1)
它绝对有可能获得对象大小,并且导致某个类的对象只是一个固定大小的内存块。我编写了以下代码来计算对象的保留大小。它还提供了一种类似于&#39; sizeof&#39;在C ++中。它已经准备就绪,完全不依赖于任何东西。你可以复制并试一试!
public class ObjectSizer {
public static final Unsafe us = getUnsafe();
public static boolean useCompressedOops = true;
public static int retainedSize(Object obj) {
return retainedSize(obj, new HashMap<Object, Object>());
}
private static int retainedSize(Object obj, HashMap<Object, Object> calculated) {
try {
if (obj == null)
throw new NullPointerException();
calculated.put(obj, obj);
Class<?> cls = obj.getClass();
if (cls.isArray()) {
int arraysize = us.arrayBaseOffset(cls) + us.arrayIndexScale(cls) * Array.getLength(obj);
if (!cls.getComponentType().isPrimitive()) {
Object[] arr = (Object[]) obj;
for (Object comp : arr) {
if (comp != null && !isCalculated(calculated, comp))
arraysize += retainedSize(comp, calculated);
}
}
return arraysize;
} else {
int objectsize = sizeof(cls);
for (Field f : getAllNonStaticFields(obj.getClass())) {
Class<?> fcls = f.getType();
if (fcls.isPrimitive())
continue;
f.setAccessible(true);
Object ref = f.get(obj);
if (ref != null && !isCalculated(calculated, ref)) {
int referentSize = retainedSize(ref, calculated);
objectsize += referentSize;
}
}
return objectsize;
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static int sizeof(Class<?> cls) {
if (cls == null)
throw new NullPointerException();
if (cls.isArray())
throw new IllegalArgumentException();
if (cls.isPrimitive())
return primsize(cls);
int lastOffset = Integer.MIN_VALUE;
Class<?> lastClass = null;
for (Field f : getAllNonStaticFields(cls)) {
if (Modifier.isStatic(f.getModifiers()))
continue;
int offset = (int) us.objectFieldOffset(f);
if (offset > lastOffset) {
lastOffset = offset;
lastClass = f.getClass();
}
}
if (lastOffset > 0)
return modulo8(lastOffset + primsize(lastClass));
else
return 16;
}
private static Field[] getAllNonStaticFields(Class<?> cls) {
if (cls == null)
throw new NullPointerException();
List<Field> fieldList = new ArrayList<Field>();
while (cls != Object.class) {
for (Field f : cls.getDeclaredFields()) {
if (!Modifier.isStatic(f.getModifiers()))
fieldList.add(f);
}
cls = cls.getSuperclass();
}
Field[] fs = new Field[fieldList.size()];
fieldList.toArray(fs);
return fs;
}
private static boolean isCalculated(HashMap<Object, Object> calculated, Object test) {
Object that = calculated.get(test);
return that != null && that == test;
}
private static int primsize(Class<?> cls) {
if (cls == byte.class)
return 1;
if (cls == boolean.class)
return 1;
if (cls == char.class)
return 2;
if (cls == short.class)
return 2;
if (cls == int.class)
return 4;
if (cls == float.class)
return 4;
if (cls == long.class)
return 8;
if (cls == double.class)
return 8;
else
return useCompressedOops ? 4 : 8;
}
private static int modulo8(int value) {
return (value & 0x7) > 0 ? (value & ~0x7) + 8 : value;
}
private static Unsafe getUnsafe() {
try {
Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
return (Unsafe) f.get(Unsafe.class);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
System.out.println(retainedSize("Hello Leeeeeeeen"));
}
}
答案 4 :(得分:0)
当您的程序正在运行时,请获取另一个终端窗口并运行:
jmap -histo <process id of the java instance you want to debug>
在输出中,它按类提供对象实例的数量和总大小。例如,3 72 java.util.Date
表示内存中有3个Date对象,每个对象占24个字节。如果相关部分滚动太快,您可能需要将输出传输到文件或其他内容。
或者,对于(更多)更多细节,请运行:
jmap -dump:format=b,file=heap.bin <processid>
jhat heap.bin
然后打开http://localhost:7000。您可以在浏览器中浏览堆上的对象。
更多信息:
http://docs.oracle.com/javase/6/docs/technotes/tools/share/jmap.html
http://docs.oracle.com/javase/6/docs/technotes/tools/share/jhat.html
我认为它总是在Sun / Oracle JVM上四舍五入到8,即使对象是12个字节,它也需要16个内存。