# 运行时数据区域
JVM内存共分为虚拟机栈、堆、方法区、程序计数器、本地方法栈五个部分。
线程私有的:
- 程序计数器 Program Counter Register
- 虚拟机栈 VM Stack
- 本地方法栈 Native Method Stack
线程共享的:
- 堆 Heap
- 方法区 Method Area
- 直接内存(直接内存并不是运行时数据区域的一部分)
# 程序计数器
程序计数器是一块较小的内存空间,是当前线程所执行的字节码的行号指示器。字节码解释器工作时,通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理等都要依赖这个计数器来完成。
每个线程都需要有一个独立的程序计数器,各个线程之间的计数器互不影响,独立存储,所以这块内存区域被称为线程私有的内存。
作用:
- 字节码解释器通过改变程序计数器来依次读取指令,从而实现代码的流程控制:顺序执行、选择、循环等。
- 在多线程的情况下,程序计数器用于记录当前线程执行的位置,从而线程被切换回来可以知道上次运行到哪。
程序计数器是唯一一个不会出现
OutOfMemoryError
的内存区域。生命周期随着线程的创建而创建,随着线程的结束而死亡。
# 虚拟机栈
Java内存可以分为堆内存和栈内存,这里的栈指的就是虚拟机栈。
虚拟机栈中的局部变量表主要存放了各种数据类型(八种基本数据类型)、对象引用(可能是指向对象起始地址的引用指针)等。
Java虚拟机会出现两种错误:
StackOverFlowError
和OutOfMemoryError
。
Java栈类比数据结构中的栈,保存的主要内容是栈帧,每次的函数调用都有对应的栈帧被压入Java栈,而每次函数的调用结束,都会有一个栈帧被弹出。
# 本地方法栈
本地方法栈与虚拟机栈的区别在于:本地方法栈是为虚拟机使用到的Native方法服务,而虚拟机栈是为执行Java(字节码)服务。「HotSpot」虚拟机中,这两个栈合二为一。
# 堆
堆是Java虚拟机中所管理的内存最大的一块,是所有线程都共享的一块区域。这块区域的目的是存放对象实例,几乎所有的对象实例以及数组都在这里分配内存。
Java堆是垃圾收集器管理的主要区域,所以也被称作GC堆。因为垃圾回收器都基本采用分代垃圾回收算法,所以Java堆还可细分为:新生代和老年代,目的是为了更好地回收内存,或者更快地分配内存。
# 方法区
方法区也是所有线程都共享的一块区域,用于存储已被虚拟机加载的类信息、常量、静态便令、即时编译后的代码等数据。
# 直接内存
直接内存并不是虚拟机运行时数据区的一部分,也不是虚拟机规范中定义的内存区域,但是这部分内存被频繁地使用。它避免了在Java堆和Native堆之间来回复制数据。