本文整理了作者在读《深入理解JVM》一书后的笔记。
java程序员把内存管理的权利交给java虚拟机。
java虚拟机在执行java程序的过程中会
把它所管理的内存划分为若干个不同的数据区域。
每个区域都有自己各自的用途,以及创建和销毁的时间。
运行时数据区
1、程序计数器(
线程私有)
是一块较小的内存空间,
作用可以看成是当前线程所执行的字节码的行号指示器。
分支,循环,跳转,异常处理,线程恢复等基础功能都需要依赖这个计数器完成。
为了线程切换后能够回到正确的执行位置,每条线程都需要有一个单独的程序计数器。
该内存区域是
唯一一个在java虚拟机规范中没有规定OutOfMemoryError的区域。
2、java虚拟机栈(
线程私有)
每个方法被创建的时候都会同时创建一个栈帧,用于存储局部变量表,操作栈,动态链接,方法出口等信息。每一个方法被调用直至完成的过程就对应着一个栈帧在虚拟机中从入栈到出栈的过程。
我们常说将java内存分为堆内存和栈内存,其中栈内存也就是这里虚拟机栈中的局部变量部分。
其中64位长度的
long和double类型的数据会占用2个局部变量空间,其余占一个。
易抛出异常:StackOverFlowError,OutOfMemoryError
如果线程请求的栈深度大于虚拟机所允许的深度,抛出StackOverFlowError异常
如果虚拟机在拓展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常
3、本地方法栈
和虚拟机栈的区别:虚拟机栈为虚拟机执行java方法(即字节码)服务,而本地方法栈则为虚拟机使用到的Native方法服务。
易抛出异常:StackOverFlowError,OutOfMemoryError
其中程序计数器,虚拟机栈,本地方法栈(前三个)这三个区域随线程而生,随线程而灭。
这几个区域不需要考虑回收问题,因为方法结束或线程结束,内存自然也就跟随着回收了。
4、Java堆(各个线程所共享的内存区域)
Java堆是java虚拟机中所管理的内存中最大的一块。
java堆被所有线程所共享,是虚拟机启动时创建。
java堆的唯一目的是存放对象实例。
Java堆是垃圾收集器管理的主要区域,因此很多时候被称为"GC堆"(Garbage Collected Heap)
Java堆可以处于物理上
不连续的内存空间中,只要是逻辑上是连续的就行。可选择固定大小和可拓展。
如果堆中没有内存完成实例分配,而且堆也无法再拓展时,将会抛出OutMemoryError异常。
5、方法区
用于存储
已被虚拟机加载的类信息,常量,静态变量,编译器编译后的代码等。
该区域
不需要连续的内存,可选择固定大小和可拓展。
当方法区无法满足内存分配需求时,将抛出OutOfMemoryError异常。
6、其他
运行时常量池:是方法区的一部分
当常量池无法再申请到内存时,会抛出OutOfMemeryError异常。
直接内存:并非虚拟机运行时数据区的一部分
但这部分内存被频繁使用,可能导致OutOfMemoryError异常。