java-jvm方法区学习(一)

方法区定义

在这里插入图片描述
方法区和堆差不多,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
方法区的大小决定了系统可以保存多少个类,如果系统定义了太多的类,导致方法区溢出,就会抛出内存溢出错误:Java.lang.OutOfMemoryErro:MetaSpace 或Java.lang.OutOfMemoryErro:PermGen space。
在JDK1.6和以前的版本中方法区是在永久代 PermGen space中,在JDK1.8中方法区是在元空间MetaSpace的本地内存里

运行时常量池和常量池

常量池

先看一个简单的案例

// 一个类的二进制字节码包括了(类的基本信息,常量池,类的方法定义,虚拟机指令)
public class Test2 {
    public static void main(String[] args) {
        System.out.println("HelloWorld");
    }
}

把它编译成class文件后反编译回来(反编译指令: javap -v ***.class)

  Last modified 2021-2-21; size 573 bytes
  MD5 checksum 0e47a72370577c678966d2f846bb6fec
  Compiled from "Test2.java"
public class com.cdyl.api.Test2
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #6.#21         // java/lang/Object."<init>":()V
   #2 = Fieldref           #22.#23        // java/lang/System.out:Ljava/io/PrintStream;
   #3 = String             #24            // HelloWorld
   #4 = Methodref          #25.#26        // java/io/PrintStream.println:(Ljava/lang/String;)V
   #5 = Class              #27            // com/cdyl/api/Test2
   #6 = Class              #28            // java/lang/Object
   #7 = Utf8               <init>
   #8 = Utf8               ()V
   #9 = Utf8               Code
  #10 = Utf8               LineNumberTable
  #11 = Utf8               LocalVariableTable
  #12 = Utf8               this
  #13 = Utf8               Lcom/cdyl/api/Test2;
  #14 = Utf8               main
  #15 = Utf8               ([Ljava/lang/String;)V
  #16 = Utf8               args
  #17 = Utf8               [Ljava/lang/String;
  #18 = Utf8               MethodParameters
  #19 = Utf8               SourceFile
  #20 = Utf8               Test2.java
  #21 = NameAndType        #7:#8          // "<init>":()V
  #22 = Class              #29            // java/lang/System
  #23 = NameAndType        #30:#31        // out:Ljava/io/PrintStream;
  #24 = Utf8               HelloWorld
  #25 = Class              #32            // java/io/PrintStream
  #26 = NameAndType        #33:#34        // println:(Ljava/lang/String;)V
  #27 = Utf8               com/cdyl/api/Test2
  #28 = Utf8               java/lang/Object
  #29 = Utf8               java/lang/System
  #30 = Utf8               out
  #31 = Utf8               Ljava/io/PrintStream;
  #32 = Utf8               java/io/PrintStream
  #33 = Utf8               println
  #34 = Utf8               (Ljava/lang/String;)V
{
  public com.cdyl.api.Test2();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 5: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/cdyl/api/Test2;

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=1, args_size=1
         0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #3                  // String HelloWorld
         5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: return
      LineNumberTable:
        line 8: 0
        line 9: 8
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       9     0  args   [Ljava/lang/String;
    MethodParameters:
      Name                           Flags
      args
}
SourceFile: "Test2.java"

在这里插入图片描述
Constant pool就是类的常量池,常量池的数据如何使用就得看虚拟机指令了

 public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=1, args_size=1
         0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #3                  // String HelloWorld
         5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: return
      LineNumberTable:
        line 8: 0
        line 9: 8
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       9     0  args   [Ljava/lang/String;
    MethodParameters:
      Name                           Flags
      args

第一句getstatic #2 获取一个静态变量指向了 #2 地址,我们去常量池中去查找#2
在这里插入图片描述
发现又指向了#22#23在这里插入图片描述
#22的class 说明指向了#29的类, #23的NameAndType是说明找一个为#30的变量和#31的类型
这一串指令最终就拼成了我们写的System.out

第二句ldc #3 加载一个为#3的变量,我们去常量池中找#3
在这里插入图片描述
发现#3->#24 string 说明是个字符串
在这里插入图片描述
最终找到#24是一个字符串的 HelloWorld
继续往下的指令invokevirtual #4 进行一次方法调用
在这里插入图片描述
在这里插入图片描述
#4->#26#25 #25说明了调用的是哪个类, #26说明方法名和类型
#26-> #33#34,找到了println方法,这时我们的一整句代码就齐了
System.out.println("HelloWorld");
最后一句指令 return 说明方法执行完毕
总结: 常量池就是一张表,虚拟机指令根据这张常量表找到要执行的类名,方法名,参数类型,字面量等信息

运行时常量池

常量池是一个*.class文件中的,当该类被加载,它的常量池信息就会被放入运行时常量池,并把里面的符号地址(#1,#2等)变为真实的内存地址

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值