Java ArrayList对象内存消耗高

Java ArrayList对象内存消耗高,java,memory-management,arraylist,amazon-s3,jvm,Java,Memory Management,Arraylist,Amazon S3,Jvm,我已经在S3中创建了大小为10^7的java对象(字符串的ArrayList)。每个条目(字符串)的大小为13字节(12个字符)。这个文件的大小约为130MB 现在,当我从S3(使用AmazonS3Client)将数据放入ArrayList对象时,机器前后的可用内存分别约为12090332712字节(11.26GB)和10334207976字节(9.62GB)。差异大约为1.64GB 现在的问题是,大约15字节大小为10^7的字符串数组列表的内存消耗不应该像它显示的那样高 一些意见: 我们将数

我已经在S3中创建了大小为10^7的java对象(字符串的ArrayList)。每个条目(字符串)的大小为13字节(12个字符)。这个文件的大小约为130MB

现在,当我从S3(使用AmazonS3Client)将数据放入ArrayList对象时,机器前后的可用内存分别约为12090332712字节(11.26GB)和10334207976字节(9.62GB)。差异大约为1.64GB

现在的问题是,大约15字节大小为10^7的字符串数组列表的内存消耗不应该像它显示的那样高

一些意见:

  • 我们将数据从S3直接流式传输到ArrayList对象。即使 如果ArrayList在达到当前容量时以1.5的速率增加, 它不应该超过300MB
  • 尝试使用char[]而不是String,因为char是基本类型,可以减少内存消耗,但事实并非如此
请让我知道我错过了什么

谢谢
Adarsh

每当
ArrayList
达到其当前限制时,将创建一个新的更大的支持数组,并复制所有旧项目。这可能会导致大量阵列只填充了一半


要避免这种情况,请使用
LinkedList
或事先测量计数,并创建满容量的数组。

每个java对象都有开销。首先,每个对象都有一些头,在64位体系结构上是16字节,可能更多。其次,字符串由包装对象和包含数组组成。第三,每个字符表示为两个字节

考虑到所有这些因素,每个字符串可能至少需要64个字节。此外,还需要存储所有字符串的数组和另一个在数组列表增大其大小之前使用的大小为一半的数组。此外,还有一些用于反序列化的临时对象

因此,数据越大,存储的数据越少,开销与实际大小之间的比率就越大。

“…15字节大小”这是您的数据部分。还有其他因素

  • 对象头:Java中的所有对象都记录它们的类
  • 对象锁:Java中的所有对象都有自己的锁,因此这会占用空间
  • Java中的字符是UTF-16=2字节
  • 内存对齐:内存中的对象不一定布局紧凑。如果一个对象在64位系统中只占用2个字节的内存,那么它实际上会占用64位(=8字节)的内存

这些只是其中的一些原因。可能还有其他问题。

如何测量可用内存?能否显示一些代码,说明您是如何执行操作的?如果字符数组没有多余的容量,我希望具有12个字符的字符串将占用12*2=24字节。加上数组的4字节引用,哈希变量的4字节,字符串引用的4字节。大约36个字节。这可能有很多原因。在解析文件时,可能会产生大量垃圾。数组大小调整也会产生垃圾。您还可以记录gc统计数据并在完整gc之后进行度量吗?即使如此,对于支持列表=>300MB的数组中的引用,每个字符串可能需要~25字节+4字节。假设阵列是所需大小的1.5倍(调整大小比率),即内存使用量仍然只有450MB。我的猜测是堆大小增加了,但没有完全使用,OP正在查看java进程本身的内存使用情况。@assylias-你说得对。这个问题不能解释OP所看到的巨大差异。如果我可以补充的话,复制的过程也相对缓慢。如果您事先知道要输入ArrayList的字符串数,那么将大大提高性能。