Skip to content

Conversation

@qksuki
Copy link
Contributor

@qksuki qksuki commented Sep 15, 2024

原文中的描述可以概况为 字符串常量池中保存了引用,但是字符串常量池位于堆内存中,保存的是对象而不是引用,引用位于栈内存中。因此我修改了两篇 md 文档中对于字符串常量池的描述,并且对 ldc 指令描述进行了修改。

另外,原文的图片中的描述也有问题。但是我无法修改图片的文字,因为图片是使用 oss 图床的。

修正字符串常量池引用的描述
同步修改字符串常量池的描述
修正序列化相关的描述
修正序列化相关描述
@qksuki qksuki changed the title 修正一些关于字符串常量池的描述 修正一些关于字符串常量池和序列化的描述 Sep 16, 2024
@qksuki
Copy link
Contributor Author

qksuki commented Sep 16, 2024

补充,序列化相关的描述也有点问题。在序列化详解中也提到了序列化不止可以序列化为二进制字节流外的数据,但是在 简单来说 中没有提及到。

修正GC算法描述问题
@qksuki
Copy link
Contributor Author

qksuki commented Sep 17, 2024

补充 x2,JVM GC 算法的分代收集算法中的描述,应该是 “复制”(Copying) 算法,不是 “标记-复制”算法。

@qksuki qksuki changed the title 修正一些关于字符串常量池和序列化的描述 修正一些关于字符串常量池,序列化,GC 算法的描述 Sep 17, 2024
@Snailclimb Snailclimb merged commit 74fc413 into Snailclimb:main Sep 18, 2024
@Snailclimb Snailclimb added the doc-bug Content error label Sep 18, 2024
@Snailclimb
Copy link
Owner

字符串常量池位于堆内存中,保存的是对象而不是引用

你的理解我还是有点搞不懂呀:

HotSpot 虚拟机中字符串常量池的实现是 src/hotspot/share/classfile/stringTable.cpp ,StringTable 可以简单理解为一个固定大小的HashTable ,容量为 StringTableSize(可以通过 -XX:StringTableSize 参数来设置),保存的是字符串(key)和 字符串对象的引用(value)的映射关系,字符串对象的引用指向堆中的字符串对象。

字符串对象存在于堆内存中,虽然JDK1.7 字符串常量池和静态变量从永久代移动了 Java 堆中,但这样按照你的说法是不是太容易让人误解了呢?

@Snailclimb
Copy link
Owner

原文中的描述可以概况为 字符串常量池中保存了引用,但是字符串常量池位于堆内存中,保存的是对象而不是引用,引用位于栈内存中。因此我修改了两篇 md 文档中对于字符串常量池的描述,并且对 ldc 指令描述进行了修改。

另外,原文的图片中的描述也有问题。但是我无法修改图片的文字,因为图片是使用 oss 图床的。

image

@Snailclimb
Copy link
Owner

原文中的描述可以概况为 字符串常量池中保存了引用,但是字符串常量池位于堆内存中,保存的是对象而不是引用,引用位于栈内存中。因此我修改了两篇 md 文档中对于字符串常量池的描述,并且对 ldc 指令描述进行了修改。

另外,原文的图片中的描述也有问题。但是我无法修改图片的文字,因为图片是使用 oss 图床的。

字节码注释:

如果字符串常量池中不存在字符串对象 “abc”,那么它首先会在字符串常量池中创建字符串对象 "abc",然后在堆内存中再创建其中一个字符串对象 "abc"。

示例代码(JDK 1.8):

String s1 = new String("abc");

对应的字节码:

// 在堆内存中分配一个尚未初始化的 String 对象。
// #2 是常量池中的一个符号引用,指向 java/lang/String 类。
// 在类加载的解析阶段,这个符号引用会被解析成直接引用,即指向实际的 java/lang/String 类。
0 new #2 <java/lang/String>
// 复制栈顶的 String 对象引用,为后续的构造函数调用做准备。
// 此时操作数栈中有两个相同的对象引用:一个用于传递给构造函数,另一个用于保持对新对象的引用,后续将其存储到局部变量表。
3 dup
// JVM 先检查字符串常量池中是否存在 "abc"。
// 如果常量池中已存在 "abc",则直接返回该字符串的引用;
// 如果常量池中不存在 "abc",则 JVM 会在常量池中创建该字符串字面量并返回它的引用。
// 这个引用被压入操作数栈,用作构造函数的参数。
4 ldc #3 <abc>
// 调用构造方法,使用从常量池中加载的 "abc" 初始化堆中的 String 对象
6 invokespecial #4 <java/lang/String.<init> : (Ljava/lang/String;)V>
// 将堆中的 String 对象引用存储到局部变量表
9 astore_1
// 返回,结束方法
10 return

ldc (load constant) 指令的确是从常量池中加载各种类型的常量,包括字符串常量、整数常量、浮点数常量,甚至类引用等。对于字符串常量,ldc 指令的行为如下:

  1. 从常量池加载字符串ldc 首先检查字符串常量池中是否已经有内容相同的字符串对象。
  2. 复用已有字符串对象:如果字符串常量池中已经存在内容相同的字符串对象,ldc 会将该对象的引用加载到操作数栈上。
  3. 没有则创建新对象并加入常量池:如果字符串常量池中没有相同内容的字符串对象,JVM 会在常量池中创建一个新的字符串对象,并将其引用加载到操作数栈中。

@Snailclimb
Copy link
Owner

原文中的描述可以概况为 字符串常量池中保存了引用,但是字符串常量池位于堆内存中,保存的是对象而不是引用,引用位于栈内存中。因此我修改了两篇 md 文档中对于字符串常量池的描述,并且对 ldc 指令描述进行了修改。

另外,原文的图片中的描述也有问题。但是我无法修改图片的文字,因为图片是使用 oss 图床的。

感谢完善,我提交了一个新版本:7cf404b

@qksuki
Copy link
Contributor Author

qksuki commented Sep 18, 2024

原文中的描述可以概况为 字符串常量池中保存了引用,但是字符串常量池位于堆内存中,保存的是对象而不是引用,引用位于栈内存中。因此我修改了两篇 md 文档中对于字符串常量池的描述,并且对 ldc 指令描述进行了修改。
另外,原文的图片中的描述也有问题。但是我无法修改图片的文字,因为图片是使用 oss 图床的。

感谢完善,我提交了一个新版本:7cf404b

嗯嗯,我是基于仓库内容产生疑问并进行推断的,有一些理解不到位的情况,感谢 Guide 哥的贡献。

@Snailclimb
Copy link
Owner

原文中的描述可以概况为 字符串常量池中保存了引用,但是字符串常量池位于堆内存中,保存的是对象而不是引用,引用位于栈内存中。因此我修改了两篇 md 文档中对于字符串常量池的描述,并且对 ldc 指令描述进行了修改。
另外,原文的图片中的描述也有问题。但是我无法修改图片的文字,因为图片是使用 oss 图床的。

感谢完善,我提交了一个新版本:7cf404b

嗯嗯,我是基于仓库内容产生疑问并进行推断的,有一些理解不到位的情况,感谢 Guide 哥的贡献。

这块确实容易有误解,我也有疏忽和理解不到位的地方,不好意思呀!持续完善!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

doc-bug Content error

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants