JAVA-8中堆上的字符串对象数

Jok*_*ker 1 java string heap-dump java-8

从这个堆栈溢出的字符串对象数量,我开始知道如果我们做一些像:

String s = new String("ABC");
Run Code Online (Sandbox Code Playgroud)

然后我们objects在堆上有两个String,一个在constant池上"ABC",

但今天我拿了堆转储,发现堆上有两个objects它自己.我使用MAT工具同样请找到下面的屏幕截图.

在此输入图像描述

所以我的查询是,如果堆上有两个对象,其中一个Char[]用于String类,另一个用于常量池,那么这意味着

String s = new String("ABC") 将总共​​创建3个对象.

Hol*_*ger 6

似乎有关于字符串文字和整个互联网上的字符串池的重复废话.只是为了强调,如何定义:

Java®虚拟机规范

2.5.3.堆

Java虚拟机具有在所有Java虚拟机线程之间共享的.堆是运行时数据区,从中分配所有类实例和数组的内存.

因此,无论虚拟机如何实现它,所有对象都存在于堆中,因为这就是定义术语堆的方式.堆是内存,所有对象实例都是从中分配的,因此,所有对象都是从堆中分配的.在过去,字符串文字和对象创建的对象通过new用于生活在不同的内存区域,但仍然,所有这些都是堆的一部分.

在最近的JVM中,所有String实例都在同一内存区域中创建,无论是为文字还是为通过创建的实例创建的new.

在任何一种情况下,管理字符串文字和"实习"字符串的字符串池都是对这些字符串的引用表.表本身可能存在于堆外,而对象则不存在.

在您的示例中,您有两个String实例和一个char[]数组,因为Strings实现为char[]数组的包装器,并且两个字符串共享数组.但这是一个实施细节.在其他(较旧的)JVM中,当使用String(String)构造函数从另一个构造一个字符串时,该数组被复制.因此,在这些JVM中,您的示例将创建两个String实例和两个char[]数组实例.

更奇特的是,使用最新的JVM和适当的配置,JVM将识别String具有不同阵列但内容相同的实例,并更改它们以共享阵列以减少内存消耗.此功能称为字符串重复数据删除.在Stack Overflow上,请参阅:Java 8的字符串重复数据删除功能.


Boh*_*ian 5

Thechar[]是一个内部字段String(毕竟,它必须将字符存储在某处)。

当询问“创建了多少对象”时,内部字段不计算在内。

如果询问由此创建了多少个对象:

Map<Integer, Integer> map = new HashMap<>();
Run Code Online (Sandbox Code Playgroud)

共识是“1”。在内部,创建了许多对象(我没有分析它,但我的猜测会超过 20 个),但实现选择不是问题的一部分。

  • @LoneWolf 如果您计算*每个* 对象,将会有更多。这不是“创建了多少对象”类型问题的意图。 (3认同)
  • 鉴于当前的实现,一个新构建的 `HashMap` 真正由该 `HashMap` 实例组成,没有其他任何东西。所有其他工件都是惰性填充的。即使将某些东西放入其中,占地面积也远没有那么昂贵。放置第一个条目会导致分配一个数组(最初全部为 `null`)和一个 `Entry` 实例。仍然只制作了三个对象。对于每个后续的 `put`,只会创建一个额外的 `Entry` 实例。好吧,猜测“*创建了多少对象*”类型的问题的意图无济于事…… (3认同)