JVM内存管理(一)

目录

代码分析

直接内存

JVM整体的情况


前言:首先需要理解的是JVM是一种规范,在不同的平台上,如果有对应平台的虚拟机,那么我们编写的Java程序都是可以在对应平台的虚拟机上边运行的,这也就是Java语言具有的跨平台能力。

代码分析

请看这段代码:

public class Person {
    public  int work()throws Exception{//一个方法对应一个栈帧
        int x =1;// iconst_1 、 istore_1
        int y =2;// iconst_2 、 istore_2
        int z =(x+y)*10;
        return  z;
    }
    public static void main(String[] args) throws Exception{
        Person person = new Person();
        person.work();  //这个  3  字节码的行号(针对 本方法偏移)
        person.hashCode();//方法属于本地方法 ---本地方法栈  4
    }
}

编译完成后的字节码指令:

C:\Users\ASUS>javap -c A:\Android\SeniorEngineer\01\ref-jvm3\out\production\ref-jvm3\ex1\Person.class
Compiled from "Person.java"
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的变量放入操作数栈
       1: istore_1   // 存储命令,将操作数栈顶的数据放入到局部变量表的下表为1的位置
       2: iconst_2   // 将值为1的变量放入操作数栈
       3: istore_2   // 存储命令,将操作数栈顶的数据放入到局部变量表的下表为2的位置
       4: iload_1    // 加载命令,将局部变量表中的下标为1的位置加载到操作数栈
       5: iload_2    // 加载命令,将局部变量表中的下标为2的位置加载到操作数栈,此时操作数栈有两个数,栈顶为2;
       6: iadd       // 首先将操作数栈里边的数据拿出来,算完之后再保存在操作数栈;
       7: bipush        10 // 这个数太大,不能用const命令,此时栈顶为10;int型该方式只能把-1,0,1,2,3,4,5(分别采用iconst_m1,iconst_0, iconst_1, iconst_2, iconst_3, iconst_4, iconst_5)送到栈顶。 对于int型,其他的数值请使用push系列命令(比如bipush)
       9: imul       // 将操作数栈的数取出来,做乘法,然后重新放入操作数栈。
      10: istore_3   // 将上边的结果存到局部变量表的第三个位置
      11: iload_3    // 方法与方法之间,返回的数据必须经过操作数栈,因为这是属于操作的数据;将局部变量表中的下标为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: aload_1
      14: invokevirtual #5                  // Method java/lang/Object.hashCode:()I
      17: pop
      18: return
}

为什么少了第八行指令?0,1,2,3,4,5,6这些都是本方法的字节码的偏移量,这是因为bipush指令比较大,占据了两个位置,所以导致少了第八行指令。

 完成出口:这个就是work方法的出口,main方法的地址也是从0开始的,work方法也是从0开始,work在main方法里边有自己的地址。所以这就是完成出口。

程序计数器:可能会重复,这个没有问题,因为虚拟机执行的时候,只会执行最顶上的栈帧。

动态链接: 与多态有关,指向运行时常量池的方法引用。

注意:如果是静态方法,那么局部变量表就没有this,因为对象对唯一的,就是这个类对象,this指的是当前对象,用来确定是哪个对象。

Java中无法直接操作一个线程。在HotSpot中,本地方法栈和虚拟机栈用的是同一块内存,没有做区分。程序计数器只能记录虚拟机栈里边的运行的方法,本地方法栈里边的他无法记录,因为这个已经和Java没有关系了。因为里边的表现形式不再是字节码了。

运行时数据区中的其他区域:

请看下边这段代码:

public class ObjectAndClass {
    static int age=18;//todo 静态变量(基本数据类型)放入方法区,准备阶段赋值0,初始化赋值18
    final static int sex=1;//todo 常量(基本数据类型)放入方法区,准备阶段赋值就是1
    final  static  ObjectAndClass object = new ObjectAndClass();//todo 成员变量指向(对象)在类加载的时候不会执行
    //构造方法  -》ObjectAndClass object = new ObjectAndClass();
    private boolean isKing;//todo 成员变量 放在哪里???

    public   static void main(String[] args) {//启动一个线程,创建一个虚拟机栈,数据结构,单个,压入一个栈帧
        int x=18;//todo 局部变量(基本数据类型)放入栈帧
         long y=1;//todo 局部变量(基本数据类型)放入栈帧
         ObjectAndClass lobject = new ObjectAndClass();//todo 局部变量 引用放入局部变量表 对象放入堆。注意,这个成员变量也需要完成构造方法,所以还会去创建一个对象。
         lobject.isKing=true;// isKing跟随对象,堆空间
         lobject.hashCode();//方法中调用方法  本地方法(C++语言写  JNI)
         ByteBuffer bb = ByteBuffer.allocateDirect(128*1024*1024);//todo 直接分配128M的直接内存
        //这个地方 分配在哪里  128M
    }
}

整体的内存分配情况:存在对象指向对象的情况。

一个类的生命周期:

直接内存

底层与unsafe这个类有关,这个类已经跨越了虚拟机的规范,JVM已经将内存虚拟化,将内存区域进行划分,但是unsafe却绕过来这个限定。如果使用unsafe来申请内存,直接操作内存。该方式绕过了JVM垃圾回收。需要自己手动进行回收。优势是可能能够提升效率。

如果想用直接内存,又担心回收的问题,可以使用这种方式,直接内存使用这种方式申请没有问题:

ByteBuffer bb = ByteBuffer.allocateDirect(128*1024*1024);//todo 直接分配128M的直接内存

里边使用了一个幽灵引用进行垃圾回收(待确定)。

JVM中的各种参数是由JVM根据操作系统的情况来进行评估,然后来确定一个合适的值。

JVM整体的情况

一般来说,一个对象经历过15次的回收,就会被放入老年代。

JHSDB是一个可视化的,可以来直接看对象的大小的工具。

参考文章:[三] java虚拟机 JVM字节码 指令集 bytecode 操作码 指令分类用法 助记符 - 腾讯云开发者社区-腾讯云

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值