ChenRuiyz 2020-07-18
程序计数器:线程私有。是一块较小的内存,是当前线程所执行的字节码的行号指示器。是Java虚拟机规范中唯一没有规定OOM(OutOfMemoryError)的区域。
Java栈:线程私有。生命周期和线程相同。是Java方法执行的内存模型。执行每个方法都会创建一个栈帧,用于存储局部变量和操作数(对象引用)。局部变量所需要的内存空间大小在编译期间完成分配。所以栈帧的大小不会改变。存在两种异常情况:若线程请求深度大于栈的深度,抛StackOverflowError。若栈在动态扩展时无法请求足够内存,抛OOM。
Java堆:所有线程共享。虚拟机启动时创建。存放对象实力和数组。所占内存最大。分为新生代(Young区),老年代(Old区)。新生代分Eden区,Servior区。Servior区又分为From space区和To Space区。Eden区和Servior区的内存比为8:1。 当扩展内存大于可用内存,抛OOM。
(1)新生代:所有新 new 出来的对象都会最先出现在新生代中,当新生代这部分内存满了之后,就会发起一次垃圾收集事件,这种发生在新生代的垃圾收集称为 Minor collections。 这种收集通常比较快,因为新生代的大部分对象都是需要回收的,那些暂时无法回收的就会被移动到老年代。全局暂停事件(Stop the World):所有小收集(minor garbage collections)都是全局暂停事件,也就是意味着所有的应用线程都需要停止,直到垃圾回收的操作全部完成。
(2)老年代:老年代用来存储那些存活时间较长的对象。 一般来说,我们会给新生代的对象限定一个存活的时间,当达到这个时间还没有被收集的时候就会被移动到老年代中。随着时间的推移,老年代也会被填满,最终导致老年代也要进行垃圾回收。这个事件叫做大收集(major garbage collection)。大收集也是全局暂停事件。通常大收集比较慢,因为它涉及到所有的存活对象。所以,对于对相应时间要求高的应用,应该将大收集最小化。此外,对于大收集,全局暂停事件的暂停时长会受到用于老年代的垃圾回收器的影响。
方法区:所有线程共享。用于存储已被虚拟机加载的类信息、常量、静态变量等数据。又称为非堆(Non – Heap)。方法区又称“永久代”。GC很少在这个区域进行,但不代表不会回收。这个区域回收目标主要是针对常量池的回收和对类型的卸载。当内存申请大于实际可用内存,抛OOM。
(3)永久代:永久代存储了描述应用程序类和方法的源数据,JVM 运行应用程序的时候需要这些源数据。 永久代由 JVM 在运行时基于应用程序所使用的类产生。 此外,Java SE 类库的类和方法可能也存储在这里。如果 JVM 发现有些类不在被其他类所需要,同时其他类需要更多的空间,这时候这些类可能就会被垃圾回收。
本地方法栈:线程私有。与Java栈类似,但是不是为Java方法(字节码)服务,而是为本地非Java方法服务。也会抛StackOverflowError和OOM。