【JVM】运行时数据区

运行时数据区

图示:
运行时数据区

Method Area(方法区)

方法区是各个线程内存共享的区域,在虚拟机启动时创建;用于存储已被虚拟机加载的类信息、常量、静态变量、即使编译器编译后的代码等数据

虽然Java虚拟机规范把方法区描述为堆的一个逻辑分布,但是方法区通常被称为Non-Heap(非堆),目的是与Java堆区分开;当方法区无法满足内存分配需求时,将抛出OutOfMemoryError异常

The Java Virtual Machine has a method area that is shared among all Java Virtual Machine threads. The method area is created on virtual machine start-up. Although the method area is logically part of the heap,… If memory in the method area cannot be made available to satisfy an allocation request, the Java Virtual Machine throws an OutOfMemoryError.

注意

  1. 方法区在JDK 8 中就是Metaspace,在JDK6或7中被称为Perm Space
  2. Run-Time Constant Pool
    Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息就是常量池,用于存存放编译时期生成的各种字面量和符号引用,这部分内容将在类加载进入方法区的运行时常量池存放;

Each run-time constant pool is allocated from the Java Virtual Machine’s method area


Heap(堆)
Java堆是Java虚拟所管理内存中最大的一块,在虚拟器启动时创建,被所有线程所共享;对象实例以及数组都在堆上分配内存空间;垃圾回收的主要区域

The Java Virtual Machine has a heap that is shared among all Java Virtual Machine threads. The heap is the run-time data area from which memory for all class instances and arrays is allocated. The heap is created on virtual machine start-up.

Java Virtual Machine Stacks(虚拟机栈)

虚拟机栈是一个线程执行的区域,保存着一个线程中方法的调用状态;换句话说,一个Java线程的运行状态,由一个虚拟机栈来保存,所以虚拟机栈肯定是线程私有的,随着线程的创建而创建;

每一个被线程执行的方法,称为该栈中栈帧,即每一个方法对应一个栈帧;一个方法被调用就会向虚拟机栈中压入一个栈帧;一个方法调用完成,就会将栈帧从栈中弹出

Each Java Virtual Machine thread has a private Java Virtual Machine stack, created at the same time as the thread. A Java Virtual Machine stack stores frames

图解

比如执行以下方法:

    public void A() {
       B();
       C();
    }

虚拟机栈存储运行如下:
虚拟机栈

栈:先进后出
A frame is used to store data and partial results, as well as to perform dynamic linking, return values for methods, and dispatch exceptions. A new frame is created each time a method is invoked. A frame is destroyed when its method invocation completes, whether that completion is normal or abrupt (it throws an uncaught exception). … Note that a frame created by a thread is local to that thread and cannot be referenced by any other thread.

栈帧

每一个栈帧对应一个方法,压栈意味着方法的调用,出栈意味着方法执行完成;

每个栈帧中包括局部变量表(Local Variables)、操作数栈(Operand Stack)、指向运行时常量池的引用(A reference to the run-time constant pool)、方法返回地址(Return Address)和附加信息

局部变量表

方法中定义的局部变量一个方法的参数存储位置;局部变量表中的变量不可以直接使用,如果需要使用的话,必须通过相关的指令将其加载到操作数中使用

操作数栈

以压栈和出栈的方式存储操作数

动态链接

每个操作数栈都包含一个指向运行时常量池中

方法返回地址

当一个方法执行后,只有两种方式可以退出,一种是遇到方法的返回地址;一种是遇见异常,并且这个异常没有在方法体内得到处理

The PC Register(程序计数器)

首先,我们来看一个问题,我们都知道以后JVM进程中有多个线程在执行,而线程中的内容是否能够执行,是根据CPU调度的;假如线程A正在执行到某个地方,突然失去了CPU的执行权。切换到了线程B,让后当线程A再次获得CPU执行权的时候,怎么能够继续执行那?那么继续要维护一下变量,用于记录线程执行的到哪一行的位置;程序计数器随之诞生。

程序计数器占用的内存空间很小,由于Java虚拟机的多线程是通过线程轮流切换,并分配处理器执行时间的方式来实现的;在任意时刻,一个处理器只会执行一条线程的指令,因此,为了线程切换后能够恢复到正确的执行位置,每条线程需要有一个独立的程序计数器(线程私有)

如果线程正在执行Java方法,则计数器记录的是正在执行的虚拟机字节码指令的地址;

如果正在执行的是Native方法,则这个计数器为空。

The Java Virtual Machine can support many threads of execution at once (JLS §17). Each Java Virtual Machine thread has its own pc (program counter) register. At any point, each Java Virtual Machine thread is executing the code of a single method, namely the current method (§2.6) for that thread. If that method is not native, the pc register contains the address of the Java Virtual Machine instruction currently being executed. If the method currently being executed by the thread is native, the value of the Java Virtual Machine’s pc register is undefined. The Java Virtual Machine’s pc register is wide enough to hold a returnAddress or a native pointer on the specific platform.

Native Method Stacks(本地方法栈)

如果当前线程执的方法时Native类型时,这些方法就会在本地方法中执行

结合字节码指令理解虚拟机栈
public class Person {
        private String name = "demo";
        private int age;
        private final double salary = 1000;
        private static String address;
        private final static String hobby = "Programming";
        private Object obj = new Object();
    
        public void say() {
            System.out.println("person say...");
        }
        
        public static int calc(int op1, int op2) {
            op1 = 3;
            int result = op1 + op2;
            return result;
        }
    
        public static void main(String[] args) {
            System.out.println(calc(1, 2));
        }
    }

    Compiled from "Person.java"
    public class Person {
      public Person();
        Code:
           0: aload_0
           1: invokespecial #1                  // Method java/lang/Object."<init>":()V
           4: aload_0
           5: ldc           #2                  // String demo
           7: putfield      #3                  // Field name:Ljava/lang/String;
          10: aload_0
          11: ldc2_w        #4                  // double 1000.0d
          14: putfield      #6                  // Field salary:D
          17: aload_0
          18: new           #7                  // class java/lang/Object
          21: dup
          22: invokespecial #1                  // Method java/lang/Object."<init>":()V
          25: putfield      #8                  // Field obj:Ljava/lang/Object;
          28: return
    
      public void say();
        Code:
           0: getstatic     #9                  // Field java/lang/System.out:Ljava/io/PrintStream;
           3: ldc           #10                 // String person say...
           5: invokevirtual #11                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
           8: return
    
      public static int calc(int, int);
        Code:
           0: iconst_3           	//将int类型常量2压入操作数栈
           1: istore_0			 	//将int类型值存入局部变量0	
           2: iload_0            	//从局部变量0中装载int类型的值
           3: iload_1            	//从局部变量1中装载int类型的值
           4: iadd              	// 执行int类型的加法
           5: istore_2          	//将int类型值存入局部变量表中
           6: iload_2            	//从局部变量2中装载int类型的值
           7: ireturn            	//从方法中返回int类型的值
    
      public static void main(java.lang.String[]);
        Code:
           0: getstatic     #9                  // Field java/lang/System.out:Ljava/io/PrintStream;
           3: iconst_1
           4: iconst_2
           5: invokestatic  #12                 // Method calc:(II)I
           8: invokevirtual #13                 // Method java/io/PrintStream.println:(I)V
          11: return
    }

主内存、工作内存与Java内存区域中的Java堆、栈、方法区等并不是同一层次的内存划分。两者基本上是没有关系的,如果两者一定要勉强对应起来的,从变量、主内存、工作内存的定义看,主内存主要对应于Java堆中的对象实例数据部分,而工作内存则对应了虚拟机栈中部分区域

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值