长久更新,个人还在学习中!
JVM内存区域
为什么要了解内存区域,Java程序员把内存控制的权力交给Java虚拟机,一旦出现内存泄漏和溢出的问题,如果不了解虚拟机内存区域是怎么使用内存的,排查错误就会很困难。
内存区域主要分为程序计数器,虚拟机栈,本地方法栈,堆,方法区。每个都有各自的用处,有的跟随线程的启动和结束来建立和销毁,有的根据虚拟机进程的启动而存在。
1.程序计数器
程序计数器是一个较小的内存空间,主要存储的是下一条指令的地址(例如线程恢复(notify)、等待(wait))。
如果线程执行的是一个Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果执行的是Native方法,则计数器值为空。
该内存区域是唯一一个在Java虚拟机规范种没有任何OutOfMemoryError(内存溢出)情况的区域。
2.虚拟机栈
主要描述的是Java方法执行的内存区域,每个方法在执行的同时会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用至完成,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。
(1)局部变量表存放了编译期可知的各种基本数据类型(8种)、对象引用(reference,不等同于对象本身,可能是一个指向对象起始地址的引用指针,也可能是指向一个代表对象的句柄或其他与此对象相关的位置)和returnAddress类型。
(2)操作数栈和局部变量表类似,局部变量表用的是索引,而操作数栈是进栈/出栈来访问。
(3)动态链接,符号引用和直接引用在运行时进行解析和链接的过程。
(4)方法出口,每个方法有两种出路,一种正常结束,一种异常,不管那种,都会返回到被调用的地方。
3.本地方法栈
本地方法栈和虚拟机栈差不多,两个的区别是虚拟机栈执行的是Java方法,而本地方法栈执行的是Native方法。不做过多讲接!
4.堆
Java堆是Java虚拟机种所管理的最大的一块。此内存区域唯一目的就是存放对象实例,是垃圾收集器管理的主要区域,所以有时也叫"GC堆"。从内存回收的角度来看,现在的收集器基本都采用分代收集算法,Java堆可以细分为:新生代和老生代;从内存分配的角度来看,Java堆种可能划分出多个线程私有的分配缓冲区(TLAB),无论怎么划分,斗鱼存放内容无关,无论那个区域,存储的都任然是对象实例,进一步划分的目的只是为了更好的回收内存,或者更快的分配内存。
5.方法区
用于存储虚拟机加载的类信息、常量、静态变量、即使编译器编译后的代码等数据。
线程私有:程序计数器,虚拟机栈,本地方法栈。
线程共享:方法区,堆。
何为线程私有,每一个线程都会有它自己的内存区域,线程共享,则为各种线程一起使用的地方。