运行时内存区域这块,如果不将内存各个区域做什么的了解清楚,后面看的会很累。
之前将JVM运行时内存区域的内容,整理在了一篇文章中。
在后续深入、细致的学习中,整理的内容越来越多,一篇的话,会导致篇幅过长。
所以将《JVM运行时内存区域详解》分为以下几个章节:
这里将《Java虚拟机规范中文版》上传了,点击下面链接,即可下载
目录
《Java Virtual Machine Specification Java SE 7 中文版》
《Java Virtual Machine's Internal Architecture》
方法区
《深入理解Java虚拟机:JVM高级特性与最佳实践》
方法区也是个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、及时编译器编译后的代码等数据。
虽然Java虚拟机规范把方法区描述为堆的一个逻辑部分,但它有一个别名叫做:Non-Heap(非堆),目的应该是与Java堆区分开来。
方法区在程序运行时被创建。
它与Java堆的区别除了存储的信息与Java堆不一样之外,最大的区别是这一部分Java虚拟机规范中不强制要求实现自动内存管理系统(GC)。
对于在HotSpot虚拟机上开发的开发者来说,很多人更愿意将方法区称为"永久代",本质上两者并不等价。
(书中的内容需要好好读上两遍,应该能够理解,这里暂时不表,下面会做解释)
《Java Virtual Machine Specification Java SE 7 中文版》
在Java虚拟机中,方法区是可供各条线程共享的运行时内存区域。
方法区与传统语言中的编译代码存储区或者操作系统进程的正文段的作用非常类似,它存储了每一个类的结构信息,例如运行
常量池、字段、方法数据、构造函数和普通方法的字节码内容、还包括一些类、实例、接口初始化时用到的特殊方法。
方法区在虚拟机启动的时候创建,虽然方法区是堆的逻辑组成部分,但是简单的虚拟机实现可以选择在这个区域不实现垃圾搜集。(不强制虚拟机实现方法区的垃圾搜集)
方法区的容量可以是固定大小的,也可以随着程序执行的需求动态扩展,并在不需要过多空间时自动收缩。
方法区在实际内存空间中可以是不连续的。
《Java Virtual Machine's Internal Architecture》
在JVM运行时数据区中,方法区的作用和堆类似,扮演的也是存储公共数据的角色。
不过方法区存储的是已加载的代码(Class-类信息 等编译后的数据)。
换个角度理解:
可以将其视为静态的硬盘。(注意和堆进行区分)
- 虚拟机启动,虚拟机使用类加载器来定位相应的类文件。
- 类加载器读入类文件(二进制数据的线性流),并将其传递给虚拟机。
- 虚拟机从二进制数据中提取信息,并将信息存储在方法区中。
- 类中声明的类(静态)变量的内存也取自方法区。
永久代和方法区的关系?
简单的说:
在Java虚拟机规范中,并没有什么"永久代"的概念,有的只是一个方法区概念。
HotSpot团队设计 HotSpot虚拟机时候偷懒,使用 永久代 来 实现 方法区;
这样子,HotSpot虚拟机的垃圾回收期就可以像管理Java堆一样管理永久代(方法区)。
其实,只要你理解了 Java虚拟机规范 和 HotSpot虚拟机 两者之间的关系,很容易就明白这二者的关系了。
(一个是接口规范,一个是接口具体实现)
方法区:Java虚拟机规范。
永久代:HotSpot虚拟机特有(其他虚拟机不了解...)。
这里我贴上从网上找的答案:
https://www.zhihu.com/question/49044988
常量池与永久代
JDK1.7开始,将原本放在"永久代"中的字符串常量池移出。
这个观点"RednaxelaFX"也在评论中做了解释:
https://www.zhihu.com/question/49044988
http://openjdk.java.net/jeps/122
https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.5.4