相对于C、C++程序员来说Java程序员应该是很幸福的,他们不需要管理自己的内存,而全部交由JVM来控制,它使得我们能够更加专注于程序功能点的开发而不去维护内存,天下苦NPE久矣,但是一旦出现内存泄漏和溢出方面的问题,如果你不了解JVM具体的运行原理,那么排查错误将是一个非常非常艰难的任务,并且如果你在书写Java程序的时候不知道它一个底层的运行原理,那么你很难书写良好的代码。
运行时数据区域
Java虚拟机咋执行Java程序的时候会把它管理的内存划分为若干个不同的数据区域
无特殊说明介绍的都是
HotSpot
虚拟机 并且JDK版本默认是1.8及以上
其中线程私有的有 1. 程序计数器 2. 虚拟机栈 3. 本地方法栈
线程共享的的有
- 堆
- 方法区
- 直接内存(即非运行时数据区的一部分)
下面让我们来针对这些内存一个一个的分析
程序计数器
- 什么是程序计数器
程序计数器是当前线程正在执行的字节码的地址,它是线程隔离的,其执行原理为字节码解释器读取内存中的字节码,按照顺序读取字节码指令,读取一个指令就把它翻译为一个固定的操作。
- 为什么需要程序计数器
在单线程来看可有可无,但是在多线程看来需要保存当前线程所执行的位置
- 程序计数器的特点
- 程序计数器是线程隔离的
- 程序计数器占用的内存空间非常小,可以忽略不计
- 程序计数器是java虚拟机规范中唯一一个没有规定任何OutOfMemoryError的区域
- 执行native本地方法时,程序计数器的值为空。原因是native方法是java通过jni调用本地C/C++库来实现,非java字节码实现,所以无法统计
Java虚拟机栈
Java虚拟机栈也是线程私有的,它的生命周期和线程周期相同,它描述了Java方法执行时的内存模型,每一次方法的调用的数据都是通过栈传递的。
Java虚拟机栈是有一个一个的栈帧组成,每个栈帧都拥有局部变量表、操作数栈、动态链接、方法出口信息。
Java虚拟机栈会出现两种错误:StackOverFlowError
和OutOfMemoryError
StackOverFlowError
:如果Java虚拟机栈的内存大小不允许动态扩展,那么当线程请求栈的深度超过当前Java虚拟机最大深度的时候就会报错OutOfMemoryError
:如果Java虚拟机堆没有空闲内存,并且垃圾回收器也无法提供更多内存的话,就会抛出OutOfMemoryError
错误
本地方法栈
本地方法栈和Java虚拟机栈的作用相似,区别为:Java虚拟机栈为虚拟机执行Java方法服务,而本地方法栈则为虚拟机使用到的Native方法服务,在HotSpot虚拟机中,Java虚拟机栈和本地方法栈合二为一。