JVM 运行时数据区 (三)

JVM运行时数据区

运行时数据区由 程序计数器、java虚拟机栈、本地方法栈、堆、方法区 组成;java

一、程序计数器

  每个Java线程都有一个程序计数器,用于保存程序执行到当前方法的哪个指令,它是线程私有的。函数

此内存区域是惟一一个在VM Spec中没有规定任何OutOfMemoryError状况的区域。spa

 

二、Java虚拟机栈

  一般说的栈指的就是Java栈,主管Java程序的运行。栈是在线程建立时建立,线程结束栈内存就释放掉了,不存在垃圾回收问题,线程一结束该栈就Over,与程序计数器同样,它的生命周期也是与线程相同,它是线程私有的线程

  基本类型的变量、实例方法、引用类型变量都是在函数的栈内存中分配3d

  栈描述的是Java方法调用的内存模型:每一个方法被执行的时候,都会同时建立一个帧(Frame)用于存储本地变量表、操做栈、动态连接、方法出入口等信息。每个方法的调用至完成,就意味着一个帧在VM栈中的入栈至出栈的过程。本地变量表存放了编译期可知的各类标量类型(boolean、byte、char、short、int、float、long、double)、对象引用(不是对象自己,仅仅是一个引用指针)、方法返回地址等指针

  这个区域规定了2种异常:若是线程请求的栈深度大于虚拟机所容许的深度,将抛出StackOverflowError异常;若是VM栈能够动态扩展(VM Spec中容许固定长度的VM栈),当扩展时没法申请到足够内存则抛出OutOfMemoryError异常。code

(1)抛出StackOverflowError异常的代码(递归调用):对象

public class StackDemo1
{
    static void sayHello()
    {
        System.out.println("AAAAA");
        sayHello();
    }

    public static void main(String[] args) {
        sayHello();
    }
}

 

三、本地方法栈

  本地方法栈和Java虚拟机栈发挥的做用是相似的,只不过Java虚拟机栈为虚拟机运行原语服务,而本地方法栈是为虚拟机使用到的 native 服务。blog

它的实现语言、结构、方式没有强制规定,甚至有的虚拟机把它和java虚拟机栈合二为一了,例如Sun Hotspot递归

  和java虚拟机栈同样,这个区域也会抛出StackOverflowError异常和OutOfMemoryError异常。

 

四、堆

  Java7以前

    一个JVM实例只存在于一个堆内存中,堆内存的大小是能够调节的。类加载器读取了类文件以后,须要把类、方法、常变量放到堆内存中,

  保存全部引用类型的真实信息,以方便执行器执行。

    堆内存逻辑上分为:新生区、养老区、永久区。(实际上永久区被称为非堆内存)

    新生区:伊甸区(Eden Space)、幸存0区(Survivor 0 Space)、幸存1区(Survivor 1 Space)

    当new 一个对象,该对象被放入伊甸区(Eden),建立的对象愈来愈多,伊甸区(Eden)快满的时候启动一种轻垃圾回收(Minor GC),未被回收的对象被放入幸存0区(Survivor 0),Eden被清空;当幸存0区快满了,未被回收的对象被放入幸存1区(Survivor 1),Survivor 0和Eden被清空;Survisor 0与Survivor 1交换角色,如此循环往复。若是对象的复制次数达到16次,该对象就会被送到养老中。当养老区快满的时候触发一个重量级的GC(Major GC),清理以后仍是没法再保存对象,就会产生OOM异常(OutOfMemoryError)。

    Survisor 0 和 Survivor 1会一直调换角色,谁是空的谁就是Survivor 1区。

         

    

    

五、方法区

  方法区是全部线程共享的,一般用来储存装载的类的元结构信息。垃圾回收不多发生;

  好比:运行时常量池 + 静态变量 + 常量 + 字段 + 方法字节码 + 在类/实例/接口初始化用到的特殊方法等。

  一般和永久区关联在一块儿(Java7),具体的跟JVM的实现和版本有关。Java8之后,变为了MetaSpace(元空间),直接使用的物理内存,垃圾回收运行的几率变得更低。

相关文章
相关标签/搜索