应用程序超出了分配给它的预期内存量,堆转储中的前三个条目如下:
num #instances #mb class name
----------------------------------------------
1: 11759890 465.61 [C
2: 3659043 292.89 [Ljava.util.HashMap$Node;
3: 11762204 282.29 java.lang.String
由于字符串由字符数组表示,因此预计会看到两者之间的相关性,在这种情况下,每个实例的数量非常相似,仅相差约 3000 个实例。
令人困惑的是两者的使用差异,因为 char[] 构成的字节比字符串多 50% 以上。
由于有问题的程序不直接包含 char 数组的实例,(尽管可能存在我忽略的依赖性),似乎 char 数组是唯一的来源,但由于内存使用,我不确定如果这是预期的。
就实例和内存使用而言,字符数组和字符串之间的预期比率是多少?在什么时候数据会表明两者之一发生泄漏?
在 Java 7,更新 6 之前,一个String
实例包含对char[]
数组和两个int
字段的引用,offset
以及length
. 再加上 HotSpot 至少两个字的 JVM 特定对象开销,它可以解释String
统计数据中每个 24 字节的平均值。
相比之下,char[]
数组具有 JVM 特定的对象开销、存储的长度int
和可变大小的内容。因此,看到显着更大的内存使用量(例如char[]
统计信息中显示的每个数组平均 40 字节)并不罕见。在不了解您特定 JVM 配置的更多信息的情况下,这有点猜测,但如果我们假设数组头有 16 个字节,包括长度和可能的填充,剩余的 24 个字节表明平均数组大小为 12char
秒,这并非不合理。
从 Java 7 更新 6 开始, 的offset
和length
字段String
消失了,对于大多数配置,每个实例的大小应该减少到 16 字节,这可以为字符串实例节省大约 100MB。并且显着改变该比率,因此char[]
实例在堆中占据更大的主导地位。
这就是为什么从 Java 9 开始,String
实例只包含对byte[]
数组的引用。如果字符串仅由 iso-latin-1 字符组成,这适用于典型应用程序中的大量字符串,则每个字符将仅使用一个字节,将这些字符串的内存量减半(准确地说是它们的数组) . 由于还会有包含该字符集之外的字符的字符串,当然,保存不会完全像那样。但也许你的应用程序还有大约 100MB。
但是,假设上面猜测的平均字符串长度,这些数组使用的内存将明显大于字符串实例使用的内存,即使在最近的实现中也是如此。这是正常的。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句