我有一个应用程序,读取一个CSV文件与成堆的数据行。我根据数据类型向用户提供了行数的摘要,但我想确保不会读入太多行数据而导致OutOfMemoryErrors。每一行转换成一个对象。有没有一种简单的方法以编程方式找出该对象的大小?是否有一个引用定义了一个VM的基本类型和对象引用有多大?

现在,我有代码说读取多达32,000行,但我还希望有代码说读取尽可能多的行,直到我使用了32MB的内存。也许这是另一个问题,但我还是想知道。


当前回答

你必须利用反射在物体上行走。做的时候要小心:

仅仅分配一个对象在JVM中就有一些开销。这个量因JVM而异,所以可以将此值作为参数。至少让它成为一个常量(8字节?),并应用于分配的任何东西。 仅仅因为一个字节理论上是1个字节,并不意味着内存中只需要一个字节。 在对象引用中会有循环,因此您需要使用object-equals作为比较器来保留HashMap或类似的东西,以消除无限循环。

@jodonnell:我喜欢你的解决方案的简单性,但许多对象是不可序列化的(所以这将抛出一个异常),字段可以是暂时的,对象可以覆盖标准方法。

其他回答

当使用JetBrains IntelliJ时,首先在|文件设置|构建,执行,部署|调试器中启用“附加内存代理”。

调试时,右键单击感兴趣的变量,选择“计算保留大小”:

如果你只是想知道在你的JVM中有多少内存被使用,有多少是空闲的,你可以尝试这样做:

// Get current size of heap in bytes
long heapSize = Runtime.getRuntime().totalMemory();

// Get maximum size of heap in bytes. The heap cannot grow beyond this size.
// Any attempt will result in an OutOfMemoryException.
long heapMaxSize = Runtime.getRuntime().maxMemory();

// Get amount of free memory within the heap in bytes. This size will increase
// after garbage collection and decrease as new objects are created.
long heapFreeSize = Runtime.getRuntime().freeMemory();

edit:我认为这可能会有帮助,因为问题作者还表示,他希望有处理“读取尽可能多的行,直到我使用了32MB内存”的逻辑。

可以使用java.lang.instrument包。

编译并将这个类放入JAR:

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 o) {
        return instrumentation.getObjectSize(o);
    }
}

将以下内容添加到您的清单中。MF:

Premain-Class: ObjectSizeFetcher

使用getObjectSize()方法:

public class C {
    private int x;
    private int y;

    public static void main(String [] args) {
        System.out.println(ObjectSizeFetcher.getObjectSize(new C()));
    }
}

调用:

java -javaagent:ObjectSizeFetcherAgent.jar C

我偶然发现了一个java类 "jdk.nashorn.internal.ir.debug. objectsizecalculator ",已经在jdk中, 这很容易使用,似乎对确定物体的大小非常有用。

System.out.println(ObjectSizeCalculator.getObjectSize(new gnu.trove.map.hash.TObjectIntHashMap<String>(12000, 0.6f, -1)));
System.out.println(ObjectSizeCalculator.getObjectSize(new HashMap<String, Integer>(100000)));
System.out.println(ObjectSizeCalculator.getObjectSize(3));
System.out.println(ObjectSizeCalculator.getObjectSize(new int[]{1, 2, 3, 4, 5, 6, 7 }));
System.out.println(ObjectSizeCalculator.getObjectSize(new int[100]));

结果:

164192
48
16
48
416

你必须利用反射在物体上行走。做的时候要小心:

仅仅分配一个对象在JVM中就有一些开销。这个量因JVM而异,所以可以将此值作为参数。至少让它成为一个常量(8字节?),并应用于分配的任何东西。 仅仅因为一个字节理论上是1个字节,并不意味着内存中只需要一个字节。 在对象引用中会有循环,因此您需要使用object-equals作为比较器来保留HashMap或类似的东西,以消除无限循环。

@jodonnell:我喜欢你的解决方案的简单性,但许多对象是不可序列化的(所以这将抛出一个异常),字段可以是暂时的,对象可以覆盖标准方法。