JVM的内存结构

来源:互联网 发布:中广核软件人员工资 编辑:程序博客网 时间:2024/06/05 18:58

大多数 JVM 将内存区域划分为

  • Method Area(Non-Heap)(方法区)
  • Heap(堆)
  • Program Counter Register(程序计数器)
  • VM Stack(虚拟机栈,也有翻译成JAVA 方法栈的)
  • Native Method Stack (本地方法栈)

    其中Method Area和Heap是线程共享的,VMStack,Native Method Stack 和Program Counter Register是非线程共享的。如图:

这里写图片描述

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

程序计数器(Program Counter Register)

是一块较小的内存空间,它的作用可以看做是当前线程所执行字节码的行号指示器。是线程私有,生命周期与线程相同。

Java虚拟机栈(Java Virtual Machine Stacks)

也是线程私有的,它的生命周期与线程相同。 Java虚拟机栈描述的是Java方法(区别于native的本地方法)执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧(Stack Frame)用于存储局部变量表、操作栈、动作链接、方法出口等信息。每个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。

本地方法栈(Native Method Stacks)

它与虚拟机栈所发挥的作用是非常相似的,其区别不过是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则为虚拟机所使用到的Native方法服务。

ps:栈区

  1. 栈中只保存基础数据类型的对象和自定义对象的引用(不是对象,对象都存放在堆区中)
  2. 每个栈中的数据(原始类型和对象引用)都是私有的,其他栈不能访问。
  3. 栈分为3个部分:基本类型变量区、执行环境上下文、操作指令区(存放操作指令)。
  4. 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等.

方法区(Method Area)

  1. 方法区又叫静态区,跟堆一样,被所有的线程共享。方法区包含所有的class和static变量。
  2. 方法区中包含的都是在整个程序中永远唯一的元素,如class,static变量。
  3. 全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。
  4. 方法区中对于每个类存储了以下数据:
    a.类及其父类的全限定名(java.lang.Object没有父类)
    b.类的类型(Class or Interface)
    c.访问修饰符(public, abstract, final)
    d.实现的接口的全限定名的列表
    e.常量池
    f.字段信息
    g.方法信息
    h.静态变量
    i.ClassLoader引用
    j.Class引用

  5. 由于方法区是所有线程共享的,所以必须保证线程安全,举例来说,如果两个类同时要加载一个尚未被加载的类,那么一个类会请求它的ClassLoader去加载需要的类,另一个类只能等待而不会重复加载。

垃圾回收在这个区域会比较少出现,这个区域内存回收的目的主要针对常量池的回收和类的卸载。

Java堆(Java Heap)

1.存储的全部是对象,每个对象都包含一个与之对应的class的信息。(class的目的是得到操作指令)
2.堆中不存放基本类型和对象引用,只存放对象本身.
3.一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。


例子

// AppMain.java//运行时, jvm 把appmain的信息都放入方法区public   class  AppMain {     //main 方法本身放入方法区。    public   static   void  main(String[] args) {         //test1是引用,所以放到栈区里, Sample是自定义对象应该放到堆里面        Sample test1 = new  Sample( " 测试1 " );           Sample test2 = new  Sample( " 测试2 " );        test1.printName();        test2.printName();    }} // Sample.java//运行时, jvm 把appmain的信息都放入方法区public   class  Sample {     /** 范例名称 */    //new Sample实例后, name 引用放入栈区里,  name 对象放入堆里    private  name;          /** 构造方法 */    public  Sample(String name) {        this .name = name;    }    /** 输出 */    //print方法本身放入 方法区里。    public   void  printName() {         System.out.println(name);    }}

这里写图片描述

  • 执行指令“java AppMain”

  • ClassLoader —— AppMain.class
    系统收到了我们发出的指令,启动了一个Java虚拟机进程,这个进程首先从classpath中找到AppMain.class文件,读取这个文件中的二进制数据,然后把Appmain类的类信息存放到运行时数据区的方法区中。这一过程称为AppMain类的加载过程。

  • 找Main()方法入口
    接着,Java虚拟机定位到方法区中AppMain类的Main()方法的字节码,开始执行它的指令。这个main()方法的第一条语句就是:
    Sample test1=new Sample(“测试1”);

  • 创建实例——Sample
    让java虚拟机创建一个Sample实例,并且使引用变量test1引用这个实例。Java虚拟机来执行这个任务:
    a. ClassLoader —— Sample.class
    Java虚拟机一看,不就是建立一个Sample实例吗,简单,于是就直奔方法区而去,找Sample类的类型信息。结果没找到,这会儿的方法区里还没有Sample类呢。Java虚拟机立马加载了Sample类,把Sample类的类型信息存放在方法区里。

    b. Sample实例
    资料找到,开工。Java虚拟机在堆区中为一个新的Sample实例分配内存, 这个Sample实例持有着指向方法区的Sample类的类型信息的引用。这里所说的引用,实际上指的是Sample类的类型信息在方法区中的内存地址,这个地址存放了在Sample实例的数据区里。

    c. 方法调用栈
    在JAVA虚拟机进程中,每个线程都会拥有一个方法调用栈,用来跟踪线程运行中一系列的方法调用过程,栈中的每一个元素就被称为栈帧,每当线程调用一个方法的时候就会向方法栈压入一个新帧。这里的帧用来存储方法的参数、局部变量和运算过程中的临时数据。

    d. 局部变量入栈
    位于“=”前的Test1是一个在main()方法中定义的一个局部变量,因此,它被会添加到了执行main()方法的主线程的JAVA方法调用栈中。而“=”将把这个test1变量指向堆区中的Sample实例,也就是说,它持有指向Sample实例的引用。

到这里,JAVA虚拟机就完成了这个简单语句的执行任务。

  • 创建另一个Sample实例
    JAVA虚拟机将继续执行后续指令,在堆区里继续创建另一个Sample实例,然后依次执行它们的printName()方法。

  • 方法执行
    当JAVA虚拟机执行test1.printName()方法时,JAVA虚拟机根据局部变量test1持有的引用,定位到堆区中的Sample实例,再根据Sample实例持有的引用,定位到方法去中Sample类的类型信息,从而获得printName()方法的字节码,接着执行printName()方法包含的指令。

Reference

  • http://blog.csdn.net/yanlove_jing/article/details/51637674
  • http://www.cnblogs.com/wangjzh/p/5258254.html
  • http://www.cnblogs.com/milton/p/4541415.html
  • https://www.zhihu.com/question/35164211/answer/68265045