Java内存区域
对于Java程序员来说,由于虚拟机的自动内存管理机制,一方面减少了Java程序员的工作,另一方面也大大减少了内存泄漏与内存移除的情况。但是,正因为Java程序员不再对内存保持持续关注,当出现了内存问题的时候,想要去解决问题也成了一项艰难的工作。因此,每一个Java程序员都应该了解Java虚拟机的内存细节,这样才不会在遇到内存问题时无计可施。
Java虚拟机规范要求的数据区
线程共享的数据区
Java堆
Java堆
(Jave Heap)是被所有线程共享的一块区域,在Java虚拟机中,它的唯一目的就是存放对象的实例。另外,它的另外一个被广泛关注的点是它是GC的主要管理对象。因此,也被称为GC堆
。
方法区
方法区
也是一个被所有线程共享的区域,它主要用存储虚拟机加载的类的信息、常量、静态变量、JIT编译后的代码。另外要注意的是,在Java虚拟机规范中把方法区归类为堆的一个逻辑部分。但我们要把它和堆区分开来,因为它们的功能并不一致。
需要注意的是,方法区的实现方式在不同的版本上发生了很大的变化。
-
在JDK1.6中,它由永久代实现。
-
在JDK1.7中,它由永久代和堆实现。
需要注意的是,方法区其实是一个概念,并非一块连续的内存区域取名为方法区。此处就可以看到,它的一部分由堆实现
-
在JDK1.8中,它彻底去掉了永久带,使用元空间(Meta space)和堆实现,元空间就是本地内存而非虚拟机内存。
class文件常量池
每个class文件都带有一个常量池,也被称作静态常量池,在类加载后,会将这部分常量池放入方法区的运行时常量池存放
运行时常量池
运行时常量池
是方法区的一部分。每个class都拥有一个运行时常量池,用于存放编译器生成的各种字面量和符号引用。
类在解析之后,会将符号引用替换成直接引用,与全局常量池中的引用值保持一致。
字符串常量池
资料说String pool存储引用,堆中存储字符串对象,每一个在String pool中的引用指向的字符串对象被标记为字符串常量。
另外字符串常量池逻辑上一定属于方法区
,但是实际存储其实我是有些迷惑的,因为资料里只说了对象被存储在堆里,但是这个
String pool也就是存储引用的这个东西在哪里存储并未提及。但一般都认为JDK1.8以后字符串常量池存储在堆里
。
线程不共享的数据区
程序计数器
程序计数器是当前线程所执行的字节码的行号指示器。通过改变这个计数器的值来完成分支、循环、跳转、异常处理、线程恢复后的继续执行等功能。
Java虚拟机栈
描述Java方法执行的内存模型,每个方法在执行的时候都会创建一个栈帧
,用来存储局部变量表、操作数栈、动态链接、方法出口。方法执行完毕,栈帧出栈。
本地方法栈
存储虚拟机使用的本地方法。并且HotSpot 虚拟机就把本地方法栈和Java虚拟机栈合二为一了。