zoukankan      html  css  js  c++  java
  • 运行时栈帧结构

    栈帧(Stack Frame) 是用于虚拟机执行时方法调用和方法执行时的数据结构,它是虚拟栈数据区的组成元素。每一个方法从调用到方法返回都对应着一个栈帧入栈出栈的过程。

    每一个栈帧在编译程序代码的时候所需要多大的局部变量表,多深的操作数栈都已经决定了,并且写入到方发表的 Code 属性之中,一次一个栈帧需要多少内存,不会受到程序运行期变量数据的影响,仅仅取决于具体的虚拟机实现。

    典型的栈帧主要由 局部变量表(Local Stack Frame)、操作数栈(Operand Stack)、动态链接(Dynamic Linking)、返回地址(Return Address)组成,如下图所示:

        public static void main(String[] args) {
            String s1 = "Hello";
            String s2 = "Hello";
         //s3虽然是动态拼接出来的字符串,但是所有参与拼接的部分都是已知的字面量,在编译期间,这种拼接会被优化,编译器直接帮你拼好,
    String s3 = "Hel" + "lo"; //Hel被包装为对象,lo被包装为对象, //然后调用 StringBuilder.append方法, //然后调用String.toStringui方法, //存入变量s4 String s4 = "Hel" + new String("lo"); //调用new 生成新对象 String s5 = new String("Hello"); String s6 = s5.intern(); String s7 = "H"; String s8 = "ello"; String s9 = s7 + s8; System.out.println(s1 == s2); // true System.out.println(s1 == s3); // true System.out.println(s1 == s4); // false System.out.println(s1 == s9); // false System.out.println(s4 == s5); // false System.out.println(s1 == s6); // true }

    其对应指令集如下: 

             0: ldc           #5                  // String Hello
             2: astore_1
             3: ldc           #5                  // String Hello
             5: astore_2
             6: ldc           #5                  // String Hello
             8: astore_3
             9: new           #6                  // class java/lang/StringBuilder
            12: dup
            13: invokespecial #7                  // Method java/lang/StringBuilder."<init>":()V
            16: ldc           #8                  // String Hel
            18: invokevirtual #9                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
            21: new           #10                 // class java/lang/String
            24: dup
            25: ldc           #11                 // String lo
            27: invokespecial #12                 // Method java/lang/String."<init>":(Ljava/lang/String;)V
            30: invokevirtual #9                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
            33: invokevirtual #13                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
            36: astore        4
            38: new           #10                 // class java/lang/String
            41: dup
            42: ldc           #5                  // String Hello
            44: invokespecial #12                 // Method java/lang/String."<init>":(Ljava/lang/String;)V
            47: astore        5
            49: aload         5
            51: invokevirtual #14                 // Method java/lang/String.intern:()Ljava/lang/String;
            54: astore        6
            56: ldc           #15                 // String H
            58: astore        7
            60: ldc           #16                 // String ello
            62: astore        8
            64: new           #6                  // class java/lang/StringBuilder
            67: dup
            68: invokespecial #7                  // Method java/lang/StringBuilder."<init>":()V
            71: aload         7
            73: invokevirtual #9                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
            76: aload         8
            78: invokevirtual #9                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
            81: invokevirtual #13                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
            84: astore        9

    常量池:

    Java中的常量池,实际上分为两种形态:静态常量池运行时常量池

         所谓静态常量池,即*.class文件中的常量池,class文件中的常量池不仅仅包含字符串(数字)字面量,还包含类、方法的信息,占用class文件绝大部分空间。

      这种常量池主要用于存放两大类常量:字面量(Literal)和符号引用量(Symbolic References),

      字面量相当于Java语言层面常量的概念,如文本字符串,声明为final的常量值等,

     符号引用则属于编译原理方面的概念,包括了如下三种类型的常量:

    • 类和接口的全限定名
    • 字段名称和描述符
    • 方法名称和描述符

         而运行时常量池,则是jvm虚拟机在完成类装载操作后,将class文件中的常量池载入到内存中,并保存在方法区中,我们常说的常量池,就是指方法区中的运行时常量池。

    运行时常量池相对于CLass文件常量池的另外一个重要特征是具备动态性,Java语言并不要求常量一定只有编译期才能产生,也就是并非预置入CLass文件中常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量放入池中,这种特性被开发人员利用比较多的就是String类的intern()方法。
    String的intern()方法会查找在常量池中是否存在一份equal相等的字符串,如果有则返回该字符串的引用,如果没有则添加自己的字符串进入常量池。
     
          常量池的好处
    常量池是为了避免频繁的创建和销毁对象而影响系统性能,其实现了对象的共享。
    例如字符串常量池,在编译阶段就把所有的字符串文字放到一个常量池中。
    (1)节省内存空间:常量池中所有相同的字符串常量被合并,只占用一个空间。
    (2)节省运行时间:比较字符串时,==比equals()快。对于两个引用变量,只用==判断引用是否相等,也就可以判断实际值是否相等。
     
  • 相关阅读:
    IIS的各种身份验证详细测试
    HTTP Error 401.3 Unauthorized Error While creating IIS 7.0 web site on Windows 7
    C/S and B/S
    WCF ContractFilter mismatch at the EndpointDispatcher exception
    Configure WCF
    Inheritance VS Composition
    Unhandled Error in Silverlight Application, code 2103 when changing the namespace
    Java RMI VS TCP Socket
    Principles Of Object Oriented Design
    Socket处理发送和接收数据包,一个小实例:
  • 原文地址:https://www.cnblogs.com/snow-man/p/10476555.html
Copyright © 2011-2022 走看看