JAVA虚拟机运行时会将JVM使用的内存划分为不同的区域,每个区域负责不同的功能,以及各个区域的创建,销毁都各不相同。
下图是JVM运行时内存数据区的划分,
图1、JVM运行时数据区
1、程序计数器
每个线程都拥有一个独立的程序计数器,用于记录当前线程所要执行的字节码指令,该类内存区域为“线程私有”内存。
2、虚拟机栈
该区域也有人称为栈内存(对应java堆内存),这个叫法不完全正确,但可以便于理解。
该区域也是线程私有的,并且与线程的生命周期相同。
主要负责方法执行的内存部分,在每个方法执行时都会创建一个栈针存储局部变量,操作数等方法相关信息,每一次方法的调用到完成,都对应一个栈针在虚拟机栈中出入栈的过程。
该区域会抛出stackOverFlowError和OutOfMemoryError错误
stackOverFlowError 是线程请求的栈深度大于虚拟机允许的深度,如下面的代码
public static void main(String[] args) { testStackOverFlow(); } public static void testStackOverFlow(){ System.out.println("stackOverFLow"); testStackOverFlow(); }
OutOfMemoryError错误就是栈空间溢出,比如局部变量过多,占用内存过大,都会产生就不举例说明
3、本地方法栈
和虚拟机栈类似,只是负责本地Native方法,也会抛出stackOverFlowError和OutOfMemoryError错误,如IO中常用的文件读写操作的Native方法,可能是C语言或者其他语言的实现。
4、JAVA堆(JAVA Heap),GC堆
JAVA堆是JAVA虚拟机管理的内存,最大,最重要的部分,是所有线程共享的区域,
也是GC(垃圾回收)的主要回收部分,
再进行划分可以分为新生代,老生代(老年代);新生代可以划分为:Eden,From Survivor,To Survivor
主要存放对象实例,可以通过配置,设置不同代的大小和垃圾回收策略,很多优化也在堆上进行实现。
堆的详细介绍:http://www.begincode.net/blog/47
该区域会抛出 OutOfMemoryError异常
5、方法区(Method Area),非堆,永久代
该区域也是线程共享的内存区域,该区域也会进行垃圾回收,但可以忽略不计,因为效果很难令人满意
主要存储虚拟机加载的类信息,常量,静态变量等
该区域会抛出OutOfMemoryError异常,主要是启动时需要加载的类,常量,静态变量等信息特别多,超过了该区域设置的内存空间,就会抛出异常,
可以看看eclipse内存设置,如果将内存设置特别小就会抛出该内存溢出异常
http://www.begincode.net/blog/50
运行时常量池:属于方法区的一部分,主要存储运行时常量,如String的intern方法产生的字符串常量。
6、直接内存
直接内存没有在图中显示,以为他并不是虚拟机运行时数据区的一部分,不归虚拟机管理,但该内存区域也会出现OutOfMemoryError异常,
该区域使用主要是在NIO的缓冲区的使用,会用到系统直接内存,因为是通过本地方法分配的内存,当本机无法分配更多的内存时就会抛出内存溢出异常