Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域。
这些区域用途不同,有各自的创建和销毁时间。
下图是JVM所管理的内存将会包括下图的数据区域:
(字符串常量池存在于堆中)
![](https://i-blog.csdnimg.cn/blog_migrate/fa73c5c3d2a803ea433cd7c46e4bdd87.png)
Notes:
1.程序计数器
是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。
2.Java堆
Java堆是Java虚拟机所管理的内存中最大的一块,是被所有线程共享的一块内存区域,唯一目的就是存放对象实例,几乎所有的对象实例都在堆上分配内存。
Java堆是垃圾收集器管理的主要区域,也叫“GC堆”。Java堆中可细分为:新生代与老年代;再细致一点,有Eden空间、From Survivor空间、To Survivor空间等。
Java堆可以处于物理上不连续的内存空间中,逻辑上连续即可。堆在实现时候,既可以实现成固定大小的,也可以是可扩展的(主流都是可扩展的,通过-Xmx和-Xms控制)。如果在堆中没有内存完成实例分配,并且堆也无法扩展时,将会抛出OutOfMemoryError异常。
3.方法区
线程共享的内存区域。他的作用是:存储已被JVM加载的类信息、常量、静态常量、即时编译器编译后的代码 等数据。
内存回收在该区域主要针对常量池的回收、对类的卸载。
当方法区无法满足内存分配需求时,将抛出OutOfMemoryError异常。
3.1 运行时常量池
运行时常量池是方法区的一部分。
class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项是常量池,用于编译期生成的各种字面量和符号引用等内容,这部分内容将在类加载后进入方法区的运行时常量池中存放。
JVM对class文件每一部分的格式都有严格规定,但对于运行时常量池,JVM没有任何细节的要求。不过,除了Class文件中描述的符号引用外,还会把翻译出来的直接引用也存储在运行时常量池中。
运行时常量池相对于Class文件常量池的另一个重要特征是具备动态性,Java并不要求常量一定只有编译期才产生,换言之,并非预置入Class文件中常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量放入池中。如String类的intern()方法。
当常量池无法再申请到内存时候,会抛出OutOfMemoryError异常。