java - 如何判断堆转储中字符串与 char[] 的比率是否表明存在问题?

标签 java memory memory-management memory-leaks heap-memory

应用程序超出了分配给它的预期内存量,堆转储中的前三个条目如下:

 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

由于字符串由 char 数组表示,因此预计两者之间存在相关性,在这种情况下,每个实例的实例数非常相似,仅相差约 3000 个实例。
令人困惑的是两者的使用差异,因为 char[] 比字符串多出 50% 以上的字节。
由于相关程序不直接包含 char 数组的实例(尽管可能存在我忽略的依赖项),因此 char 数组似乎是唯一的源,但由于内存使用情况,我不确定如果这是预期的。

在实例和内存使用方面,字符数组和字符串之间的预期比率是多少?数据何时表明两者之一发生泄漏?

最佳答案

在 Java 7 之前,更新 6 String 实例由对 char[] 数组和两个 int 字段的引用组成,偏移量长度。与 HotSpot 的至少两个字的 JVM 特定对象开销一起,它可以解释统计信息中每个 String 的平均 24 字节。

相比之下,char[] 数组具有 JVM 特定的对象开销、存储为 int 的长度和可变大小内容。因此,看到显着增加的内存使用量(例如统计信息中显示的每个 char[] 数组平均 40 字节)并不罕见。如果不了解有关特定 JVM 配置的更多信息,这有点猜测,但如果我们假设数组头有 16 个字节(包括长度和可能的填充),则剩余 24 个字节表明平均数组大小为 12 个字符s,这也不无道理。

从 Java 7 更新 6 开始,Stringoffsetlength 字段消失了,这应该将大小减少到 16 个字节对于大多数配置,每个实例可以节省约 100MB 的字符串实例。并且显着改变比率,因此 char[] 实例在堆中占据更多主导地位。

这就是为什么从 Java 9 开始,String 实例仅包含对 byte[] 数组的引用。如果字符串仅由 iso-latin-1 字符组成(这适用于典型应用程序中的许多字符串),则每个字符将仅使用一个字节,从而将这些字符串的内存量减半(准确地说是其数组) 。当然,由于还会有包含该字符集之外的字符的字符串,因此保存不会完全一样。但也许您的应用程序还需要大约 100MB。

但是,假设上面猜测的平均字符串长度,这些数组使用的内存将明显大于字符串实例使用的内存,即使在最新的实现下也是如此。这很正常。

关于java - 如何判断堆转储中字符串与 char[] 的比率是否表明存在问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52056635/

相关文章:

java - 只有一个有效的测试用例,我可以节省编写失败测试用例的时间吗? (我可以自动生成它们吗)

java - 使用 gradle 6.3、OpenJDK 14 和 OpenJFX 14 部署 JavaFX 应用程序

powershell - Redis 服务器不能运行超过 1024M 的 maxheap

java - 方法区和 PermGen

c# - 在进程之间共享 dll - 虚拟内存似乎没有好处

java - Hibernate ResultTransformer 无法转换单个列

java - 如何使用 ant 显示构建失败

c - strncpy 在不同 IDE 中的行为

python - 存储整数列表的最有效方法

matlab - 是否有可能返回在多个单元格中包含一个实例的单元格数组?