JAVA-8 中堆上的字符串对象数
Number of String Objects on heap in JAVA-8
从这个 Number of String Objects 堆栈溢出,我开始知道如果我们做一些事情,比如:
String s = new String("ABC");
然后我们有两个 objects
,一个在堆上,即 String
,一个在 constant
池上,即 "ABC"
,
但是今天我进行了堆转储,发现自己的堆上有两个 objects
。我使用了同样的 MAT 工具,请看下面的屏幕截图。
所以我的查询是如果堆上有两个对象,一个是 Char[]
,另一个是 String
class,另一个是常量池,那么这意味着那
String s = new String("ABC")
将总共创建 3 个对象。
每个 Java String
对象都有一个 private final char value[];
表示 String
的不可变内容(参见源代码)。
这似乎反映了您在堆分析中看到的内容。
表示内场
char[]value
没有关于游泳池。
并且新的 String 构造函数复制了原始字符串,它已经是字符串
char[]
是String
的一个内部字段(毕竟它要在某处存储字符)。
询问时不计算内部字段 "how many objects are created"。
如果问这个创建了多少个对象:
Map<Integer, Integer> map = new HashMap<>();
共识是“1”。在内部,创建了很多对象(我没有分析过,但我的猜测会超过20个),但是实现选择不是问题的一部分。
关于字符串文字和字符串池的胡说八道似乎遍布整个互联网。只是为了强调,heap 是如何定义的:
The Java® Virtual Machine Specification
2.5.3. Heap
The Java Virtual Machine has a heap that is shared among all Java Virtual Machine threads. The heap is the run-time data area from which memory for all class instances and arrays is allocated.
因此,无论虚拟机如何实现它,所有对象都存在于堆中,这就是术语 heap 的定义。堆是内存,所有对象实例都是从堆中分配的,因此,所有对象都是从堆中分配的。过去,字符串文字的对象和通过 new
创建的对象曾经位于不同的内存区域,但所有这些仍然是堆的一部分。
在最近的 JVM 中,所有 String
个实例都在同一内存区域中创建,无论是为文字创建的还是为通过 new
.
创建的实例创建的
在任何一种情况下,管理字符串文字和“interned”字符串的字符串池是对这些字符串的 引用 的 table。 table 本身可能位于堆外,而对象则不然。
在您的示例中,您有两个 String
实例和一个 char[]
数组,因为 String
是作为 char[]
数组的包装器实现的,并且两个字符串共享大批。但这是一个实现细节。在其他(较旧的)JVM 中,当您使用 String(String)
构造函数从另一个字符串构造一个字符串时,该数组会被复制。因此,在这些 JVM 中,您的示例将创建两个 String
实例和两个 char[]
数组实例。
更奇特的是,使用最新的 JVM 和适当的配置,JVM 将识别 String
个具有不同数组但内容相同的实例,并将它们更改为共享一个数组以减少内存消耗。此功能称为 String Deduplication. On Stack Overflow, see: 。
从这个 Number of String Objects 堆栈溢出,我开始知道如果我们做一些事情,比如:
String s = new String("ABC");
然后我们有两个 objects
,一个在堆上,即 String
,一个在 constant
池上,即 "ABC"
,
但是今天我进行了堆转储,发现自己的堆上有两个 objects
。我使用了同样的 MAT 工具,请看下面的屏幕截图。
所以我的查询是如果堆上有两个对象,一个是 Char[]
,另一个是 String
class,另一个是常量池,那么这意味着那
String s = new String("ABC")
将总共创建 3 个对象。
每个 Java String
对象都有一个 private final char value[];
表示 String
的不可变内容(参见源代码)。
这似乎反映了您在堆分析中看到的内容。
表示内场
char[]value
没有关于游泳池。
并且新的 String 构造函数复制了原始字符串,它已经是字符串
char[]
是String
的一个内部字段(毕竟它要在某处存储字符)。
询问时不计算内部字段 "how many objects are created"。
如果问这个创建了多少个对象:
Map<Integer, Integer> map = new HashMap<>();
共识是“1”。在内部,创建了很多对象(我没有分析过,但我的猜测会超过20个),但是实现选择不是问题的一部分。
关于字符串文字和字符串池的胡说八道似乎遍布整个互联网。只是为了强调,heap 是如何定义的:
The Java® Virtual Machine Specification
2.5.3. Heap
The Java Virtual Machine has a heap that is shared among all Java Virtual Machine threads. The heap is the run-time data area from which memory for all class instances and arrays is allocated.
因此,无论虚拟机如何实现它,所有对象都存在于堆中,这就是术语 heap 的定义。堆是内存,所有对象实例都是从堆中分配的,因此,所有对象都是从堆中分配的。过去,字符串文字的对象和通过 new
创建的对象曾经位于不同的内存区域,但所有这些仍然是堆的一部分。
在最近的 JVM 中,所有 String
个实例都在同一内存区域中创建,无论是为文字创建的还是为通过 new
.
在任何一种情况下,管理字符串文字和“interned”字符串的字符串池是对这些字符串的 引用 的 table。 table 本身可能位于堆外,而对象则不然。
在您的示例中,您有两个 String
实例和一个 char[]
数组,因为 String
是作为 char[]
数组的包装器实现的,并且两个字符串共享大批。但这是一个实现细节。在其他(较旧的)JVM 中,当您使用 String(String)
构造函数从另一个字符串构造一个字符串时,该数组会被复制。因此,在这些 JVM 中,您的示例将创建两个 String
实例和两个 char[]
数组实例。
更奇特的是,使用最新的 JVM 和适当的配置,JVM 将识别 String
个具有不同数组但内容相同的实例,并将它们更改为共享一个数组以减少内存消耗。此功能称为 String Deduplication. On Stack Overflow, see: