从零出发--啃透这迷人该死的JVM---内存区域(1)

  1. 运行时数据区域:Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域
    在jvm中,jvm内存主要分为堆,程序计数器,方法区,虚拟机栈和本地方法栈等。

    同时按照与线程的关系也可以这么划分:线程私有区域与线程共享区域。
    线程私有区域:一个线程拥有单独的一份内存区域。
    线程共享区域:被所有线程共享,且只有一份。

    除了以上,还有一个直接内存,虽然直接内存不是运行时数据区的一部分,但是会被频繁的使用。例如:操作 系统上有 8G 内存,被 JVM 虚拟化了 3G,那么还剩余 5G, JVM 是借助一些工具使用这 5G 内存的,这个内存部分称之为直接内存
    在这里插入图片描述

  2. Java方法的运行与虚拟机栈
    虚拟机栈是线程运行Java方法所需的数据,指令,返回地址存储的地方。在我们实际的代码中,一个线程是可以运行多个方法的。

public class MethodAndStack {
    public static void main(String[] args) {
        A();
    }
    public static void A(){
        B();
    }
    public static void B(){
        C();
    }
    public static void C(){

    }
}

这段代码很简单,就是起一个 main 方法,在 main 方法运行中调用 A 方法,A 方法中调用 B 方法,B 方法中运行 C 方法。 我们把代码跑起来,线程 1 来运行这段代码, 线程 1 跑起来,就会有一个对应 的虚拟机栈,同时在执行每个方法的时候都会打包成一个栈帧。 比如 main 开始运行,打包一个栈帧送入到虚拟机栈。
在这里插入图片描述
C 方法运行完了,C 方法出栈,接着 B 方法运行完了,B 方法出栈、接着 A 方法运行完了,A 方法出栈,最后 main 方法运行完了,main 方法这个栈帧就 出栈了。 这个就是 Java 方法运行对虚拟机栈的一个影响。虚拟机栈就是用来存储线程运行方法中的数据的。而每一个方法对应一个栈帧。

  1. 虚拟机栈:是一种先进后出的数据结构,在jvm运行过程中存储当前线程运行方法所需要的数据,指令,返回地址

    虚拟机栈是基于线程的:哪怕你只有一个 main() 方法,也是以线程的方式运行的。在线程的生命周期中,参与计算的数据会频繁地入栈和出栈,栈的生 命周期是和线程一样的。
    虚拟机栈的大小缺省为 1M,可用参数 –Xss 调整大小,例如-Xss256k
    在这里插入图片描述
    参考官方文档:https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html

    每个Java方法被调用时都会创建一个栈帧,并入栈,一旦方法完成相应的调用,则出栈。
    栈帧大体都包含四个区域(局部变量表,操作数栈,动态连接,返回地址)

    1.局部变量表:用于存放我们的局部变量的(方法中的变量) 。首先它是一个 32 位的长度,主要存放我们的 Java 的八大基础数据类型,一般 32 位就可以存放下,如果是 64 位的就使用高低位占用两个也可以存放下,如果是局部的一些对象,比如我们的 Object 对象,我们只需要存放它的一个引用地址即可。

    2.操作数栈:存放 java 方法执行的操作数的,它就是一个栈,先进后出的栈结构,操作数栈,就是用来操作的,操作的的元素可以是任意的 java 数据类型,所 以我们知道一个方法刚刚开始的时候,这个方法的操作数栈就是空的。

    3.动态连接: Java 语言特性多态

    4.返回地址:正常返回(调用程序计数器中的地址作为返回)、异常的话(通过异常处理器表<非栈帧中的>来确定) 同时,虚拟机栈这个内存也不是无限大,它有大小限制,默认情况下是 1M。 如果我们不断的往虚拟机栈中入栈帧,但是就是不出栈的话,那么这个虚拟机栈就会爆掉。

  2. 程序计数器

    当前线程执行的字节码的行号指示器;各线程之间独立存储,互不影响。程序计数器是一块很小的内存空间,主要用来记录各个线程执行的字节码的地址,例如,分支、循环、跳转、异常、线程恢复等都依赖于计数器。 由于 Java 是多线程语言,当执行的线程数量超过 CPU 核数时,线程之间会根据时间片轮询争夺 CPU 资源。

    如果一个线程的时间片用完了,或者是其它原因导致这个线程的 CPU 资源被提前抢夺,那么这个退出的线程就需要单独的一个程序计数器,来记录下一条运行的指令。 因为 JVM 是虚拟机,内部有完整的指令与执行的一套流程,所以在运行 Java 方法的时候需要使用程序计数器(记录字节码执行的地址或行号) ,如果 是遇到本地方法(native 方法),这个方法不是 JVM 来具体执行,所以程序计数器不需要记录了,这个是因为在操作系统层面也有一个程序计数器,这个 会记录本地代码的执行的地址,所以在执行 native 方法时,JVM 中程序计数器的值为空(Undefined)。 另外程序计数器也是 JVM 中唯一不会 OOM(OutOfMemory)的内存区域。

  3. 栈帧执行对内存区域的影响

public class Person {
    public  int work()throws Exception{
        int x =1;
        int y =2;
        int z =(x+y)*10;
        return  z;
    }
    public static void main(String[] args) throws Exception{
        Person person = new Person();//person 栈中--、  new  Person  对象是在堆
        person.work();

        person.hashCode();

    }
}

首先对class进行反汇编

public class ex1.Person {
  public ex1.Person();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public int work() throws java.lang.Exception;
    Code:
       0: iconst_1
       1: istore_1
       2: iconst_2
       3: istore_2
       4: iload_1
       5: iload_2
       6: iadd
       7: bipush        10
       9: imul
      10: istore_3
      11: iload_3
      12: ireturn

  public static void main(java.lang.String[]) throws java.lang.Exception;
    Code:
       0: new           #2                  // class ex1/Person
       3: dup
       4: invokespecial #3                  // Method "<init>":()V
       7: astore_1
       8: aload_1
       9: invokevirtual #4                  // Method work:()I
      12: pop
      13: return
}

在执行work方法时,
iconst_1指令将常量1加载到操作数栈在这里插入图片描述
istore_1指令将数值1从操作数栈存储到局部变量表在这里插入图片描述
iconst_2,istore_2和以上相同

iload_1,iload_2将x,y两个局部变量加载到操作数栈
在这里插入图片描述
执行iadd加法指令
在这里插入图片描述
bipush指令将10加载到操作数栈
在这里插入图片描述
imul指令经过乘法运算后,结果返回到操作数栈中,然后通过istore指令将结果从操作数栈加载到局部变量表,iload再将最后的结果加载到操作数栈进行ireturn指令返回到上级方法。在这里插入图片描述
在这里插入图片描述
以上就是一个虚拟机栈的具体过程,指令参考地址:https://cloud.tencent.com/developer/article/1333540

今天就啃到这,明天继续~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值