java运行时内存管理

java运行时内存管理

  • Java运行时的数据区
    这里写图片描述

  • 各个部分的数据简介

    1. 程序计数器(线程私有

      是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器。字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。

    2. Java虚拟机栈(线程私有,生命周期与线程相同)

      由一系列栈帧构成,用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一次的方法调用创建一个帧,并压栈。

    3. 本地方法栈

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

    4. Java堆(与程序开发最密切)

      Java堆(Java Heap)是Java虚拟机所管理的内存中最大的一块。Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例

    5. 方法区(保存装载的类信息。)

      方法区(Method Area)与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。

  • Java对象的创建过程

    虚拟机遇到一条new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有,那必须先执行相应的类加载过程,接下来虚拟机将为新生对象分配内存。

    举个栗子:下图是对下面执行代码的图解

    这里写图片描述

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class AppMain {
    // 运行时, jvm 把appmain的信息都放入方法区
    public static void main(String[] args){
    //main 方法本身放入方法区。
    Sample test1 = new Sample( " 测试1 " );
    //test1是引用,所以放到栈区里, Sample是自定义对象应该放到堆里面
    test1.printName();
    }
    }

  • Jvm的内存模型(重点)

    –每一个线程有一个工作内存和主存独立

    –工作内存存放主存中变量的值的拷贝

    这里写图片描述

    • 当数据从主内存复制到工作存储时,必须出现两个动作:第一,由主内存执行的读(read)操作;第二,由工作内存执行的相应的load操作;
    • 当数据从工作内存拷贝到主内存时,也出现两个操作:第一个,由工作内存执行的存储(store)操作;第二,由主内存执行的相应的写(write)操作。

    每一个操作都具有原子性,不会中断。由于工作内存的存在,所以在另一个线程中的变量值被修改其他线程使用该变量时并不会得到最新的变量值,可以可以通过Volatile关键字使得在其他线程中立即可见。