五大分区是jvm运行时的数据区,是描述类加载时,经过解析储存到特定的数据区。先说五大分区分别是:程序计数器、虚拟机栈、本地方法栈、堆、方法区;其中前三个区是线程私有的,用来处理程序允许时的问题;后两个区是线程共享的,处理数据存储问题。 二者分别处理不同的问题,所以才会有堆栈分离。
方法区
和堆一样,是所有线程共享的内存区域,可以动态扩展。用来存储类的信息,如:方法、方法名、返回值、常量等。当方法区无法满足内存分配需求时,会抛OutOfMemoryError。
版本问题:为了与堆分开,方法区又叫非堆或永久代;从jdk1.7开始,已经准备去永久代,HotSpot 中已经把原来的字符串常量池、静态变量转移到堆内存。jdk1.8中,永久代已经不存在,存储的类信息都移动到元空间中,元空间直接占用本地内存。
堆
是所有线程共享的一块内存,用来存放new出来的对象信息、全局变量。
程序计数器
指向当前线程正在执行的行号,保证线程切换时能回到程序调用的位置。例如:在a方法里调用b方法,代码依次向下执行,执行到调用b方法那一行时,指针会记录这个位置,然后去执行b方法,当b执行完,指针会重新回到a方法里。
由于JVM中,多线程是轮流切换来获得CPU执行时间的,任意时间,一个cpu内核只会执行一条线程的指令;所以这就要求每个线程切换后能够恢复到切换之前的位置,也就是每个线程有自己独立的程序计数器,因此每个计数器是线程私有的。而且程序计数器存储的数据所占空间的大小不会随程序执行而改变,也就不会发生OutOfMemory内存溢出。
虚拟机栈
也就是通常的栈内存,是Java方法执行的内存模型。描述的是线程进栈出栈的过程,线程结束时内存自动释放。主要用来存储当前线程运行方法所需的数据、指令、返回地址(即局部变量和正在调用的方法),方法在调用时会在栈中开辟一块空间栈帧,方法就在栈帧中运行。另:如果线程的请求的栈深度大于虚拟机的深度,就会抛出StackOverflowError异常,例如:死循环
本地方法栈
和虚拟机栈类似,只是描述的是虚拟机用到的native方法出栈和入栈的过程,其底层是C语言。