我有一个应用程序,读取一个CSV文件与成堆的数据行。我根据数据类型向用户提供了行数的摘要,但我想确保不会读入太多行数据而导致OutOfMemoryErrors。每一行转换成一个对象。有没有一种简单的方法以编程方式找出该对象的大小?是否有一个引用定义了一个VM的基本类型和对象引用有多大?
现在,我有代码说读取多达32,000行,但我还希望有代码说读取尽可能多的行,直到我使用了32MB的内存。也许这是另一个问题,但我还是想知道。
我有一个应用程序,读取一个CSV文件与成堆的数据行。我根据数据类型向用户提供了行数的摘要,但我想确保不会读入太多行数据而导致OutOfMemoryErrors。每一行转换成一个对象。有没有一种简单的方法以编程方式找出该对象的大小?是否有一个引用定义了一个VM的基本类型和对象引用有多大?
现在,我有代码说读取多达32,000行,但我还希望有代码说读取尽可能多的行,直到我使用了32MB的内存。也许这是另一个问题,但我还是想知道。
当前回答
使用java visual VM即可。
它具有分析和调试内存问题所需的一切。
它还有一个OQL(对象查询语言)控制台,可以让你做很多有用的事情,其中之一是sizeof(o)
其他回答
这个答案与对象大小无关,而是当你使用数组来容纳对象时;它将为对象分配多少内存大小。
所以数组,列表,或map所有这些集合不会真正存储对象(只有在使用原语时,需要实际对象的内存大小),它只存储这些对象的引用。
现在在集合中使用的堆内存= sizeOfObj + sizeOfRef(* 4字节)
(4/8字节)取决于(32/64位)操作系统
原语
int [] intArray = new int [1]; will require 4 bytes.
long [] longArray = new long [1]; will require 8 bytes.
对象
Object[] objectArray = new Object[1]; will require 4 bytes. The object can be any user defined Object.
Long [] longArray = new Long [1]; will require 4 bytes.
我的意思是说,所有对象REFERENCE只需要4个字节的内存。它可能是字符串引用或双对象引用,但根据对象创建所需的内存会有所不同。
例)如果我为下面的类ReferenceMemoryTest创建对象,那么将创建4 + 4 + 4 = 12字节的内存。当您尝试初始化引用时,内存可能会有所不同。
class ReferenceMemoryTest {
public String refStr;
public Object refObj;
public Double refDoub;
}
因此,当创建对象/引用数组时,它的所有内容都将被NULL引用占用。我们知道每个引用需要4个字节。
最后,下面代码的内存分配为20字节。
参考内存测试ref1 = new参考内存测试();(4(ref1) + 12 = 16字节) 参考内存测试ref2 = ref1;(4(ref2) + 16 = 20字节)
一个可能的答案是2022年。
https://github.com/ehcache/sizeof
https://mvnrepository.com/artifact/org.ehcache/sizeof
https://mvnrepository.com/artifact/org.ehcache/sizeof/0.4.0
版本0.4.0只有一个(编译)依赖
https://mvnrepository.com/artifact/org.slf4j/slf4j-api
这是一件好事。
示例代码:
//import org.ehcache.sizeof.SizeOf;
SizeOf sizeOf = SizeOf.newInstance(); // (1)
long shallowSize = sizeOf.sizeOf(someObject); // (2)
long deepSize = sizeOf.deepSizeOf(someObject); // (3)
当我在Twitter工作时,我写了一个计算深度对象大小的实用程序。它考虑了不同的内存模型(32位,压缩oops, 64位),填充,子类填充,在循环数据结构和数组上正确工作。你可以编译这个。java文件;它没有外部依赖:
https://github.com/twitter/commons/blob/master/src/java/com/twitter/common/objectsize/ObjectSizeCalculator.java
还有内存测量器工具(以前在谷歌Code,现在在GitHub上),它很简单,在商业友好的Apache 2.0许可下发布,就像在类似的问题中讨论的那样。
如果您想测量内存字节消耗,它也需要一个java解释器的命令行参数,但在其他方面似乎工作得很好,至少在我使用它的场景中是这样。
首先,“对象的大小”在Java中并不是一个定义明确的概念。你可以指对象本身,包括它的成员、对象和它引用的所有对象(引用图)。您可以指内存中的大小或磁盘上的大小。JVM可以优化字符串之类的东西。
所以唯一正确的方法是用一个好的分析器(我使用YourKit)询问JVM,这可能不是你想要的。
然而,从上面的描述来看,似乎每一行都是自包含的,没有很大的依赖树,因此序列化方法在大多数jvm上可能是一个很好的近似方法。最简单的方法如下:
Serializable ser;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(ser);
oos.close();
return baos.size();
请记住,如果对象具有公共引用,这将不会给出正确的结果,并且序列化的大小并不总是与内存中的大小匹配,但这是一个很好的近似值。如果您将ByteArrayOutputStream大小初始化为一个合理的值,代码将会更有效。