jvm_book icon indicating copy to clipboard operation
jvm_book copied to clipboard

Page46: "方法区...用于存储...静态变量...等数据"可能不够准确

Open istarwyh opened this issue 5 years ago • 6 comments

书籍已经在后文提到了JDK7时字符串常量池、静态变量等已经被移出永久代这节标题开始对方法区的介绍或许应该分成JDK7前后两部分介绍.

istarwyh avatar Jul 01 '20 12:07 istarwyh

这个描述没有问题。你的想法也是很多人有的思维误区。

方法区是在《JVMS》中定义的逻辑区域,这个逻辑区域的职责是明确的,即存本issus标题中提到的那些数据。 而HotSpot使用的各种途径,无论是元空间、永久代,抑或是J9使用的Native Memory,都是这个逻辑区域的一类实现。《JVMS》允许并且提倡公有设计、私有实现,所以这些数据在实现层面上放在哪里——哪怕是无视运行时性能,实现为存储在磁盘、网络上,都不影响它们是方法区的一部分,是运行时数据区域的一部分。

fenixsoft avatar Jul 02 '20 02:07 fenixsoft

明白了,谢谢您的解答!

istarwyh avatar Jul 02 '20 02:07 istarwyh

@fenixsoft 作者您好,我想记得您在原书P49介绍方法区时候强调过,方法区虽然是堆的一个逻辑部分,但是有一个别名叫非堆(Not Heap), 目的是与堆区分开来,而您在原书P272也里面却提到,在JDK 7 及之后, 类变量(也就是静态变量)会随着Class对象一起存放到Java堆中,这些数据不是存放在方法区吗? 这里说的Java堆是不是就是指方法区? 也就是方法区在JDK 8 中的实现——元空间?

Kyrie-yx-Irving avatar Aug 27 '20 10:08 Kyrie-yx-Irving

@fenixsoft 作者您好,我想记得您在原书P49介绍方法区时候强调过,方法区虽然是堆的一个逻辑部分,但是有一个别名叫非堆(Not Heap), 目的是与堆区分开来,而您在原书P272也里面却提到,在JDK 7 及之后, 类变量(也就是静态变量)会随着Class对象一起存放到Java堆中,这些数据不是存放在方法区吗? 这里说的Java堆是不是就是指方法区? 也就是方法区在JDK 8 中的实现——元空间?

从你的描述中我感觉你是否混淆了“Heap”和“Java Heap”的概念。

Heap是计算机体系结构中做dynamic memory allocation的空间,这个概念在主流计算机体系结构中,对任何一个进程是普适的。

Java Heap是Java虚拟机中的做dynamic memory allocation的空间,是JVM专有的概念。由于JVM本身也是一个进程,所以它也有自己的Heap,JVM中的Java Heap、Method Area等运行时区域都实现在Heap中。 方法区的别名Non-Heap指的是它虽然实现在Heap中,但在Java视角上看却不是为用于dynamic memory allocation的空间的意思。不能把Non-Heap理解成Non-Java Heap的意思。

fenixsoft avatar Aug 27 '20 11:08 fenixsoft

@fenixsoft 谢谢作者指明堆和Java堆的区别,我之前确实混淆了这个两个概念, 但这里我想说的是,您在原书P46提到:

方法区(Method Area) 与Java堆一样, 是各个线程共享的内存区域, 它用于存储已被虚拟机加载 的类型信息、 常量、 静态变量、 即时编译器编译后的代码缓存等数据。 虽然《Java虚拟机规范》 中把 方法区描述为堆的一个逻辑部分, 但是它却有一个别名叫作“非堆”(Non-Heap) , 目的是与Java堆区 分开来。

但是您在原书中P272却提到:

准备阶段是正式为类中定义的变量(即静态变量, 被static修饰的变量) 分配内存并设置类变量初 始值的阶段, 从概念上讲, 这些变量所使用的内存都应当在方法区中进行分配, 但必须注意到方法区 本身是一个逻辑上的区域, 在JDK 7及之前, HotSpot使用永久代来实现方法区时, 实现是完全符合这 种逻辑概念的; 而在JDK 7及之后, 类变量则会随着Class对象一起存放在Java堆中, 这时候“类变量在 方法区”就完全是一种对逻辑概念的表述了, 关于这部分内容, 笔者已在4.3.1节介绍并且验证过。

这段话中您提到“ 而在JDK 7及之后, 类变量则会随着Class对象一起存放在Java堆中”, 这里提到的类变量,如果我没理解错的话应该也就是静态变量吧,Class对象我没理解错的话应该是类型信息吧? 这里信息按照《JVMS》不都应该存储在方法区吗?怎么存储到Java堆去了?

Kyrie-yx-Irving avatar Aug 27 '20 11:08 Kyrie-yx-Irving

这段话中您提到“ 而在JDK 7及之后, 类变量则会随着Class对象一起存放在Java堆中”, 这里提到的类变量,如果我没理解错的话应该也就是静态变量吧,Class对象我没理解错的话应该是类型信息吧? 这里信息按照《JVMS》不都应该存储在方法区吗?怎么存储到Java堆去了?

如果是对这个有疑问的话,在4.3.1中应该已经解释并通过JHSDB实际验证过了。你可以先看一下那部分实验,以下是书中此实验的结论:

从《Java虚拟机规范》所定义的概念模型来看,所有Class相关的信息都应该存放在方法区之中,但方法区该如何实现,《Java虚拟机规范》并未做出规定,这就成了一件允许不同虚拟机自己灵活把握的事情。JDK 7及其以后版本的HotSpot虚拟机选择把静态变量与类型在Java语言一端的映射Class对象存放在一起,存储于Java堆之中,从我们的实验中也明确验证了这一点 。

fenixsoft avatar Aug 27 '20 12:08 fenixsoft