JVM内存分区

一个 Java 源程序文件,会被编译为字节码文件(以 class 为扩展名),每个java程序都需要运行在自己的JVM上,然后告知 JVM 程序的运行入口,再被 JVM 通过字节码解释器加载运行。那么程序开始运行后,都是如何涉及到各内存区域的呢?

概括地说来,JVM初始运行的时候都会分配好Method Area(方法区)Heap(堆),而JVM 每遇到一个线程,就为其分配一个Program Counter Register(程序计数器), VM Stack(虚拟机栈)和Native Method Stack (本地方法栈),当线程终止时,三者(虚拟机栈,本地方法栈和程序计数器)所占用的内存空间也会被释放掉。这也是为什么我把内存区域分为线程共享和非线程共享的原因,非线程共享的那三个区域的生命周期与所属线程相同,而线程共享的区域与JAVA程序运行的生命周期相同,所以这也是系统垃圾回收的场所只发生在线程共享的区域(实际上对大部分虚拟机来说知发生在Heap上)的原因。

堆区(Heap)

堆区是Java虚拟机所管理的内存中最大的一块内存区域,也是被线程共享的内存区域,该内存区域存放对象以及数组(但不是所有的对象实例都在堆中)等。

方法区(Method Area)

方法区也称"永久代",它用于存储虚拟机加载的类信息、常量、静态变量,是各个线程共享的内存区域。

虚拟机栈(JVM Stack)

虚拟机栈描述的是方法执行的内存模型:每个方法被执行的时候都会创建一个"栈帧",栈帧用于存储局部变量表(包括参数)、操作栈、方法出口等信息。虚拟机栈为线程私有。

本地方法栈(Native Stack)

与虚拟机栈基本类似,区别在于虚拟机栈为虚拟机执行的方法服务,而本地方法栈则是为Native方法服务。本地方法栈为线程私有。

程序计数器(PC Register)

程序计数器是JVM内存区域中最小的一块区域,它是当前线程所执行的字节码的行号指示器,在虚拟机的模型里,字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、异常处理、线程恢复等基础功能都需要依赖计数器完成。

直接内存

直接内存并不是虚拟机内存的一部分,也不是Java虚拟机规范中定义的内存区域。jdk1.4中新加入的NIO,引入了通道与缓冲区的IO方式,它可以调用Native方法直接分配堆外内存,这个堆外内存就是直接内存,它不会影响到堆内存的大小。

例子

class JVMShowcase {
    //静态类常量,
    public final static String ClASS_CONST = "I'm a Const";
    //私有实例变量
    private int instanceVar = 15;

    public static void main(String[] args) {
        //调用静态方法
        runStaticMethod();
        //调用非静态方法
        JVMShowcase showcase = new JVMShowcase();
        showcase.runNonStaticMethod(100);
    }

    //常规静态方法
    public static String runStaticMethod() {
        return ClASS_CONST;
    }

    //非静态方法
    public int runNonStaticMethod(int parameter) {
        int methodVar = this.instanceVar * parameter;
        return methodVar;
    }
}
 第 1 步 ,向操作系统申请空闲内存。JVM 对操作系统说“给我 64M(随便模拟数据,并不是真实数据) 空闲内存”,于是,JVM 向操作系统申请空闲内存作系统就查找自己的内存分配表,找了段 64M 的内存写上“Java 占用”标签,然后把内存段的起始地址和终止地址给 JVM,JVM 准备加载类文件。
     第 2 步,分配内存内存。JVM 分配内存。JVM 获得到 64M 内存,首先给 heap 分个内存,然后给栈内存也分配好。
     第 3 步,文件检查和分析class 文件。若发现有错误即返回错误。
     第 4 步,加载类。加载类。由于没有指定加载器,JVM 默认使用 bootstrap 加载器,就把 rt.jar 下的所有类都加载到了堆类存的Method Area,JVMShow 也被加载到内存中。
   第 5 步、执行方法。执行 main 方法。执行启动一个线程,开始执行 main 方法。
     第 6 步,释放内存。释放内存。运行结束,JVM 向操作系统发送消息,说“内存用完了,我还给你”,运行结束。
posted @ 2019-03-31 23:43  xiayq  阅读(183)  评论(0编辑  收藏  举报