设置最大堆大小会影响字符串池大小吗?

时间:2020-04-05 12:59:34

标签: java string memory jvm java-11

我有一个Java应用程序,它的内存使用情况很奇怪,我注意到内存使用量明显高于最大堆大小("devDependencies": { "@angular-devkit/build-angular": "0.900.7", "@angular-devkit/build-optimizer": "0.900.7", Xmx,使用率是800m

在此之前的最近更改之一是正在使用的唯一字符串的大量增加,因此我认为也许我在堆外使用了很多内存的许多字符串-这可能吗?

我正在运行Java 11。

编辑:

例如,在this article中提到:

当我们使用new()运算符创建String对象时,它总是在堆内存中创建一个新对象。 另一方面,如果我们使用String文字语法创建对象,例如“ Baeldung”,它可能会从字符串池中返回一个现有对象(如果已经存在)。

给人两个不同的印象-堆和字符串池。

3 个答案:

答案 0 :(得分:3)

在JDK中,包含内部字符串的字符串池由两部分组成:

  1. 散列表是按堆分配的,其中包含对嵌入字符串的引用。此内存区域在“本机内存跟踪”报告中显示为“字符串表”。
  2. 内联字符串的内容。这些是Java堆中的常规java.lang.String对象。

因此,字符串池同时具有堆上和堆外部分。堆外部分通常较小,但是如果应用程序创建过多的内部字符串,它仍会占用大量额外的内存。

使用Native Memory Tracking查找String表消耗的内存量。

请参见this answer,以查找该进程可能比-Xmx占用更多内存的其他原因。

答案 1 :(得分:2)

自Java 7开始,字符串池已成为常规堆的一部分(请参见here)。因此,常规堆大小也会限制字符串池的大小。

您应该从那篇文章中学到的是,new String(...)总是创建一个新的String对象,该对象不同于以前创建的所有String对象。对应于字符串文字的String对象不是这种情况。

我注意到内存消耗明显高于最大堆大小(Xmx为800m,使用率为1.4g)。

对此的解释是,JVM使用多种方式来使用不属于常规堆的内存。这些包括:

  • JVM可执行文件及其共享库的内存
  • 用于由应用程序加载的本机代码库的内存
  • 用于Java线程堆栈的内存段
  • 用于表示元空间的内存...,其中包含JIT编译的本机代码,等等,
  • 本机代码分配的“本机”堆中的
  • 内存;例如使用malloc
  • 分配给直接缓冲区的内存

答案 2 :(得分:-1)

您可以使用https://visualvm.github.io/index.html分析和检查例如您占用的内存和堆。