Java进阶之深入理解对象与垃圾回收机制常见面试题

内存泄漏和内存溢出辨析

内存溢出:实实在在的内存空间不足导致;
内存泄漏:该释放的对象没有释放,多见于自己使用容器保存元素的情况下。

常量池与String

常量池

常量池有很多说法,包括运行时常量池、class文件常量池、字符串常量池。
虚拟机规范只规定以上区域属于方法区,并没有规定虚拟机厂商的实现。

严格来说常量池只分为静态常量池运行时常量池。JDK1.7版本之后,运行时常量池转移到堆内存中了,这里指的是物理空间,而逻辑上还是属于方法区(方法区是逻辑分区)。

一些概念:
字面量:
给基本类型变量赋值的方式就叫做字面量或者字面值
比如:int i=120; long j=10L;
符号引用:包括类和方法的全限定名(例如 String 这个类,它的全限定名就是 Java/lang/String,所以Java/lang/String就是一个符号引用)、字段的名称和描述符以及方法的名称和描述符。
直接引用:具体对象的索引值。

静态常量池

静态常量池是指class文件中的常量池,用于存放字符串字面量、符号引用以及类和方法的信息。

可以使用javap命令查看下面java代码对应的字节码中的常量池

/**
 * @author King老师
 * 栈帧执行对内存区域的影响
 */
public class Person {
    
    

    public int work() throws Exception {
    
    //运行过程中,打包一个栈帧
        int x = 1;//x是一个局部变量
        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();
        int i = 12;
    }
}

进入 Person.class所在目录,执行:javap -v Person.class

  Last modified 2020820; size 731 bytes
  SHA-256 checksum 326bd51b63d835ab4e480d26c8345b11db4d260c0da6a5a8770f3f6ca2867e28
  Compiled from "Person.java"
public class com.example.javaadvanced.jvm.ex1.Person
  minor version: 0
  major version: 51
  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
  this_class: #2                          // com/example/javaadvanced/jvm/ex1/Person
  super_class: #6                         // java/lang/Object
  interfaces: 0, fields: 0, methods: 3, attributes: 1
Constant pool:
   #1 = Methodref          #6.#30         // java/lang/Object."<init>":()V
   #2 = Class              #31            // com/example/javaadvanced/jvm/ex1/Person
   #3 = Methodref          #2.#30         // com/example/javaadvanced/jvm/ex1/Person."<init>":()V
   #4 = Methodref          #2.#32         // com/example/javaadvanced/jvm/ex1/Person.work:()I
   #5 = Methodref          #6.#33         // java/lang/Object.hashCode:()I
   #6 = Class              #34            // java/lang/Object
   #7 = Utf8               <init>
   #8 = Utf8               ()V
   #9 = Utf8               Code
  #10 = Utf8               LineNumberTable
  #11 = Utf8               LocalVariableTable
  #12 = Utf8               this
  #13 = Utf8               Lcom/example/javaadvanced/jvm/ex1/Person;
  #14 = Utf8               work
  #15 = Utf8               ()I
  #16 = Utf8               x
  #17 = Utf8               I
  #18 = Utf8               y
  #19 = Utf8               z
  #20 = Utf8               Exceptions
  #21 = Class              #35            // java/lang/Exception
  #22 = Utf8               main
  #23 = Utf8               ([Ljava/lang/String;)V
  #24 = Utf8               args
  #25 = Utf8               [Ljava/lang/String;
  #26 = Utf8               person
  #27 = Utf8               i
  #28 = Utf8               SourceFile
  #29 = Utf8               Person.java
  #30 = NameAndType        #7:#8          // "<init>":()V
  #31 = Utf8               com/example/javaadvanced/jvm/ex1/Person
  #32 = NameAndType        #14:#15        // work:()I
  #33 = NameAndType        #36:#15        // hashCode:()I
  #34 = Utf8               java/lang/Object
  #35 = Utf8               java/lang/Exception
  #36 = Utf8               hashCode
{
    
    
  public com.example.javaadvanced.jvm.ex1.Person();
    descriptor: ()V
    flags: (0x0001) 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 7: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/example/javaadvanced/jvm/ex1/Person;

  public int work() throws java.lang.Exception;
    descriptor: ()I
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=2, locals=4, args_size=1
         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
      LineNumberTable:
        line 10: 0
        line 11: 2
        line 12: 4
        line 13: 11
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      13     0  this   Lcom/example/javaadvanced/jvm/ex1/Person;
            2      11     1     x   I
            4       9     2     y   I
           11       2     3     z   I
    Exceptions:
      throws java.lang.Exception

  public static void main(java.lang.String[]) throws java.lang.Exception;
    descriptor: ([Ljava/lang/String;)V
    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=3, args_size=1
         0: new           #2                  // class com/example/javaadvanced/jvm/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: bipush        12
        20: istore_2
        21: return
      LineNumberTable:
        line 17: 0
        line 18: 8
        line 19: 13
        line 20: 18
        line 21: 21
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      22     0  args   [Ljava/lang/String;
            8      14     1 person   Lcom/example/javaadvanced/jvm/ex1/Person;
           21       1     2     i   I
    Exceptions:
      throws java.lang.Exception
}
SourceFile: "Person.java"

上面信息中的Constant pool:里面的内容就是静态常量池中的数据。

运行时常量池

而运行时常量池存放的是运行时的直接引用和字符串常量池。
在类加载完成之后,将静态常量池中的符号引用替换成直接引用放入运行时常量池,将静态常量池中的字符串放入运行时常量池。

String 对象是如何实现的?

重要其实还是String。

了解了 String 对象的实现后,你有没有发现在实现代码中 String 类被 final 关键字修饰了,而且变量 char 数组也被 final 修饰了。我们知道类被 final 修饰代表该类不可继承,而 char[]被 final+private 修饰,代表了 String 对象不可被更改。Java 实现的这个特性叫作 String 对象的不可变性,即 String 对象一旦创建成功,就不能再对它进行改变。

Java中创建字符串对象的两种方式:

一种是通过字符串常量的方式创建,如 String str=“abc”;
这种方式,首先在代码编译时,字符串常量“abc”将会放入class文件的静态常量池中,在类加载时,“abc"将会在运行时常量池中创建;
在这里插入图片描述

运行时返回常量池中的字符串对象的引用。

这种方式可以减少同一个值的字符串对象的重复创建,节约内存。

另一种是字符串变量通过 new 形式的创建,如 String str = new String(“abc”)
这种方式,首先在代码编译时,字符串常量"abc"将会放入class文件的静态常量池中,在类加载时,“abc"将会在运行时常量池中创建;
在这里插入图片描述

其次,在调用 new 时,JVM 命令将会在堆内存中创建一个 String 对象,调用 String 的构造函数,String对象的char数组会引用常量池中的"abc” 字符串对象;最后,str 将引用堆中创建的 String 对象。在这里插入图片描述

String 的 intern 方法

如果调用String 的 intern 方法,会去查看字符串常量池中是否有等于该字符串对象的字符串(通过 equals(Object)方法判断),如果没有,则会把该字符串对象添加到常量池中,并返回常量池中该字符串对象的引用;如果有,就返回常量池中的字符串对象的引用。(这个版本都是基于JDK1.7及以后版本)

代码实战

public class Location {
    
    

    private String city;
    private String region;


    public static void testStringCreate() {
    
    

        Location location = new Location();
        location.setCity("深圳");//"深圳"和"南山"两个字符串在常量池中创建
        location.setRegion("南山");

        //JVM首先会检查该对象是否在字符串常量池中,如果在,就返回该对象引用,否则新的字符串将在常量池中被创建。
        //这种方式可以减少同一个值的字符串对象的重复创建,节约内存。
        String str = "abc";


        //首先在编译类文件时,"abcd"常量字符串将会放入到常量结构中,在类加载时,“abcd"将会在常量池中创建;
        //其次,在调用 new 时,JVM 命令将会调用 String 的构造函数,同时引用常量池中的"abcd” 字符串,
        // 在堆内存中创建一个 String 对象;最后,str 将引用 String 对象。
        String str1 = new String("abcd");


    }

    /**
     * String的intern()方法
     */
    public static void testStringIntern() {
    
    
        //new Sting() 会在堆内存中创建一个a的String对象,
        // “king"将会在常量池中创建
        // 在调用intern方法之后,会去常量池中查找是否有等于该字符串对象的字符串(通过equals(Object)判断是否相等),
        // 有就返回常量池中该字符串对象的引用。 否则就将该字符串"king"加入常量池中,并返回该字符串的引用4
        String a = new String("king").intern();

        //调用 new Sting() 会在堆内存中创建一个b的String 对象,。
        // 在调用intern方法之后,会去常量池中查找是否有等于该字符串对象的字符串(通过equals(Object)判断是否相等),
        // 有就返回常量池中该字符串对象的引用。 否则就将该字符串"king"加入常量池中,并返回该字符串的引用
        String b = new String("king").intern();
        //所以 a 和 b 引用的是同一个对象, 都是指string pool中的"king"
        if (a == b) {
    
    
            System.out.println("a==b");
        } else {
    
    
            System.out.println("a!=b");
        }

    }


    /**
     * 字符串拼接
     *
     * String的+操作的实现原理
     */
    public static void testStringConcat() {
    
    
        String hello = "hello";
        String hel = "hel";
        String lo = "lo";

//		+ 两边都是常量,编译时会在class常量池中放置拼接后的字符串"hello",类加载后放入运行时常量池,
//		hello1指向的是运行时常量池中的"hello"字符串对象。
        String hello1 = "hel" + "lo";
        System.out.println(hello == hello1); //true

//		+ 两边有一个不是常量
        String hello2 = "hel" + lo;
        System.out.println(hello == hello2);//false

        String hello3 = hel + lo;
        System.out.println(hello == hello3);//false
        System.out.println(hello2 == hello3);//false

        //常量池中只有"appleorange"字符串对象,没有"apple"字符串对象,也没有"orange"字符串对象
        String str = "apple" + "orange";
    }


    public static void main(String[] args) {
    
    

        testStringCreate();
        testStringConcat();
        testStringIntern();

    }

    public String getCity() {
    
    
        return city;
    }

    public void setCity(String city) {
    
    
        this.city = city;
    }

    public String getRegion() {
    
    
        return region;
    }

    public void setRegion(String region) {
    
    
        this.region = region;
    }
}

执行:javap -v Location.class

  Last modified 2020821; size 2265 bytes
  SHA-256 checksum 177a9cc73d0d275d8f200e7104d1b12c6e404d32d7d52bee8f5095134225db58
  Compiled from "Location.java"
public class com.example.javaadvanced.jvm.ex2.Location
  minor version: 0
  major version: 51
  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
  this_class: #2                          // com/example/javaadvanced/jvm/ex2/Location
  super_class: #32                        // java/lang/Object
  interfaces: 0, fields: 2, methods: 9, attributes: 1
Constant pool:
    #1 = Methodref          #32.#72       // java/lang/Object."<init>":()V
    #2 = Class              #73           // com/example/javaadvanced/jvm/ex2/Location
    #3 = Methodref          #2.#72        // com/example/javaadvanced/jvm/ex2/Location."<init>":()V
    #4 = String             #74           // 深圳
    #5 = Methodref          #2.#75        // com/example/javaadvanced/jvm/ex2/Location.setCity:(Ljava/lang/String;)V
    #6 = String             #76           // 南山
    #7 = Methodref          #2.#77        // com/example/javaadvanced/jvm/ex2/Location.setRegion:(Ljava/lang/String;)V
    #8 = String             #78           // abc
    #9 = Class              #79           // java/lang/String
   #10 = String             #80           // abcd
   #11 = Methodref          #9.#81        // java/lang/String."<init>":(Ljava/lang/String;)V
   #12 = String             #82           // king
   #13 = Methodref          #9.#83        // java/lang/String.intern:()Ljava/lang/String;
   #14 = Fieldref           #84.#85       // java/lang/System.out:Ljava/io/PrintStream;
   #15 = String             #86           // a==b
   #16 = Methodref          #87.#88       // java/io/PrintStream.println:(Ljava/lang/String;)V
   #17 = String             #89           // a!=b
   #18 = String             #53           // hello
   #19 = String             #54           // hel
   #20 = String             #55           // lo
   #21 = Methodref          #87.#90       // java/io/PrintStream.println:(Z)V
   #22 = Class              #91           // java/lang/StringBuilder
   #23 = Methodref          #22.#72       // java/lang/StringBuilder."<init>":()V
   #24 = Methodref          #22.#92       // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   #25 = Methodref          #22.#93       // java/lang/StringBuilder.toString:()Ljava/lang/String;
   #26 = String             #94           // appleorange
   #27 = Methodref          #2.#95        // com/example/javaadvanced/jvm/ex2/Location.testStringCreate:()V
   #28 = Methodref          #2.#96        // com/example/javaadvanced/jvm/ex2/Location.testStringConcat:()V
   #29 = Methodref          #2.#97        // com/example/javaadvanced/jvm/ex2/Location.testStringIntern:()V
   #30 = Fieldref           #2.#98        // com/example/javaadvanced/jvm/ex2/Location.city:Ljava/lang/String;
   #31 = Fieldref           #2.#99        // com/example/javaadvanced/jvm/ex2/Location.region:Ljava/lang/String;
   #32 = Class              #100          // java/lang/Object
   #33 = Utf8               city
   #34 = Utf8               Ljava/lang/String;
   #35 = Utf8               region
   #36 = Utf8               <init>
   #37 = Utf8               ()V
   #38 = Utf8               Code
   #39 = Utf8               LineNumberTable
   #40 = Utf8               LocalVariableTable
   #41 = Utf8               this
   #42 = Utf8               Lcom/example/javaadvanced/jvm/ex2/Location;
   #43 = Utf8               testStringCreate
   #44 = Utf8               location
   #45 = Utf8               str
   #46 = Utf8               str1
   #47 = Utf8               testStringIntern
   #48 = Utf8               a
   #49 = Utf8               b
   #50 = Utf8               StackMapTable
   #51 = Class              #79           // java/lang/String
   #52 = Utf8               testStringConcat
   #53 = Utf8               hello
   #54 = Utf8               hel
   #55 = Utf8               lo
   #56 = Utf8               hello1
   #57 = Utf8               hello2
   #58 = Utf8               hello3
   #59 = Class              #101          // java/io/PrintStream
   #60 = Utf8               main
   #61 = Utf8               ([Ljava/lang/String;)V
   #62 = Utf8               args
   #63 = Utf8               [Ljava/lang/String;
   #64 = Utf8               getCity
   #65 = Utf8               ()Ljava/lang/String;
   #66 = Utf8               setCity
   #67 = Utf8               (Ljava/lang/String;)V
   #68 = Utf8               getRegion
   #69 = Utf8               setRegion
   #70 = Utf8               SourceFile
   #71 = Utf8               Location.java
   #72 = NameAndType        #36:#37       // "<init>":()V
   #73 = Utf8               com/example/javaadvanced/jvm/ex2/Location
   #74 = Utf8               深圳
   #75 = NameAndType        #66:#67       // setCity:(Ljava/lang/String;)V
   #76 = Utf8               南山
   #77 = NameAndType        #69:#67       // setRegion:(Ljava/lang/String;)V
   #78 = Utf8               abc
   #79 = Utf8               java/lang/String
   #80 = Utf8               abcd
   #81 = NameAndType        #36:#67       // "<init>":(Ljava/lang/String;)V
   #82 = Utf8               king
   #83 = NameAndType        #102:#65      // intern:()Ljava/lang/String;
   #84 = Class              #103          // java/lang/System
   #85 = NameAndType        #104:#105     // out:Ljava/io/PrintStream;
   #86 = Utf8               a==b
   #87 = Class              #101          // java/io/PrintStream
   #88 = NameAndType        #106:#67      // println:(Ljava/lang/String;)V
   #89 = Utf8               a!=b
   #90 = NameAndType        #106:#107     // println:(Z)V
   #91 = Utf8               java/lang/StringBuilder
   #92 = NameAndType        #108:#109     // append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   #93 = NameAndType        #110:#65      // toString:()Ljava/lang/String;
   #94 = Utf8               appleorange
   #95 = NameAndType        #43:#37       // testStringCreate:()V
   #96 = NameAndType        #52:#37       // testStringConcat:()V
   #97 = NameAndType        #47:#37       // testStringIntern:()V
   #98 = NameAndType        #33:#34       // city:Ljava/lang/String;
   #99 = NameAndType        #35:#34       // region:Ljava/lang/String;
  #100 = Utf8               java/lang/Object
  #101 = Utf8               java/io/PrintStream
  #102 = Utf8               intern
  #103 = Utf8               java/lang/System
  #104 = Utf8               out
  #105 = Utf8               Ljava/io/PrintStream;
  #106 = Utf8               println
  #107 = Utf8               (Z)V
  #108 = Utf8               append
  #109 = Utf8               (Ljava/lang/String;)Ljava/lang/StringBuilder;
  #110 = Utf8               toString
{
    
    
  public com.example.javaadvanced.jvm.ex2.Location();
    descriptor: ()V
    flags: (0x0001) 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 3: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/example/javaadvanced/jvm/ex2/Location;

  public static void testStringCreate();
    descriptor: ()V
    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
    Code:
      stack=3, locals=3, args_size=0
         0: new           #2                  // class com/example/javaadvanced/jvm/ex2/Location
         3: dup
         4: invokespecial #3                  // Method "<init>":()V
         7: astore_0
         8: aload_0
         9: ldc           #4                  // String 深圳
        11: invokevirtual #5                  // Method setCity:(Ljava/lang/String;)V
        14: aload_0
        15: ldc           #6                  // String 南山
        17: invokevirtual #7                  // Method setRegion:(Ljava/lang/String;)V
        20: ldc           #8                  // String abc
        22: astore_1
        23: new           #9                  // class java/lang/String
        26: dup
        27: ldc           #10                 // String abcd
        29: invokespecial #11                 // Method java/lang/String."<init>":(Ljava/lang/String;)V
        32: astore_2
        33: return
      LineNumberTable:
        line 11: 0
        line 12: 8
        line 13: 14
        line 17: 20
        line 23: 23
        line 26: 33
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            8      26     0 location   Lcom/example/javaadvanced/jvm/ex2/Location;
           23      11     1   str   Ljava/lang/String;
           33       1     2  str1   Ljava/lang/String;

  public static void testStringIntern();
    descriptor: ()V
    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
    Code:
      stack=3, locals=2, args_size=0
         0: new           #9                  // class java/lang/String
         3: dup
         4: ldc           #12                 // String king
         6: invokespecial #11                 // Method java/lang/String."<init>":(Ljava/lang/String;)V
         9: invokevirtual #13                 // Method java/lang/String.intern:()Ljava/lang/String;
        12: astore_0
        13: new           #9                  // class java/lang/String
        16: dup
        17: ldc           #12                 // String king
        19: invokespecial #11                 // Method java/lang/String."<init>":(Ljava/lang/String;)V
        22: invokevirtual #13                 // Method java/lang/String.intern:()Ljava/lang/String;
        25: astore_1
        26: aload_0
        27: aload_1
        28: if_acmpne     42
        31: getstatic     #14                 // Field java/lang/System.out:Ljava/io/PrintStream;
        34: ldc           #15                 // String a==b
        36: invokevirtual #16                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        39: goto          50
        42: getstatic     #14                 // Field java/lang/System.out:Ljava/io/PrintStream;
        45: ldc           #17                 // String a!=b
        47: invokevirtual #16                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        50: return
      LineNumberTable:
        line 36: 0
        line 41: 13
        line 43: 26
        line 44: 31
        line 46: 42
        line 49: 50
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
           13      38     0     a   Ljava/lang/String;
           26      25     1     b   Ljava/lang/String;
      StackMapTable: number_of_entries = 2
        frame_type = 253 /* append */
          offset_delta = 42
          locals = [ class java/lang/String, class java/lang/String ]
        frame_type = 7 /* same */

  public static void testStringConcat();
    descriptor: ()V
    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
    Code:
      stack=3, locals=7, args_size=0
         0: ldc           #18                 // String hello
         2: astore_0
         3: ldc           #19                 // String hel
         5: astore_1
         6: ldc           #20                 // String lo
         8: astore_2
         9: ldc           #18                 // String hello
        11: astore_3
        12: getstatic     #14                 // Field java/lang/System.out:Ljava/io/PrintStream;
        15: aload_0
        16: aload_3
        17: if_acmpne     24
        20: iconst_1
        21: goto          25
        24: iconst_0
        25: invokevirtual #21                 // Method java/io/PrintStream.println:(Z)V
        28: new           #22                 // class java/lang/StringBuilder
        31: dup
        32: invokespecial #23                 // Method java/lang/StringBuilder."<init>":()V
        35: ldc           #19                 // String hel
        37: invokevirtual #24                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        40: aload_2
        41: invokevirtual #24                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        44: invokevirtual #25                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
        47: astore        4
        49: getstatic     #14                 // Field java/lang/System.out:Ljava/io/PrintStream;
        52: aload_0
        53: aload         4
        55: if_acmpne     62
        58: iconst_1
        59: goto          63
        62: iconst_0
        63: invokevirtual #21                 // Method java/io/PrintStream.println:(Z)V
        66: new           #22                 // class java/lang/StringBuilder
        69: dup
        70: invokespecial #23                 // Method java/lang/StringBuilder."<init>":()V
        73: aload_1
        74: invokevirtual #24                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        77: aload_2
        78: invokevirtual #24                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        81: invokevirtual #25                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
        84: astore        5
        86: getstatic     #14                 // Field java/lang/System.out:Ljava/io/PrintStream;
        89: aload_0
        90: aload         5
        92: if_acmpne     99
        95: iconst_1
        96: goto          100
        99: iconst_0
       100: invokevirtual #21                 // Method java/io/PrintStream.println:(Z)V
       103: getstatic     #14                 // Field java/lang/System.out:Ljava/io/PrintStream;
       106: aload         4
       108: aload         5
       110: if_acmpne     117
       113: iconst_1
       114: goto          118
       117: iconst_0
       118: invokevirtual #21                 // Method java/io/PrintStream.println:(Z)V
       121: ldc           #26                 // String appleorange
       123: astore        6
       125: return
      LineNumberTable:
        line 58: 0
        line 59: 3
        line 60: 6
        line 64: 9
        line 65: 12
        line 68: 28
        line 69: 49
        line 71: 66
        line 72: 86
        line 73: 103
        line 76: 121
        line 77: 125
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            3     123     0 hello   Ljava/lang/String;
            6     120     1   hel   Ljava/lang/String;
            9     117     2    lo   Ljava/lang/String;
           12     114     3 hello1   Ljava/lang/String;
           49      77     4 hello2   Ljava/lang/String;
           86      40     5 hello3   Ljava/lang/String;
          125       1     6   str   Ljava/lang/String;
      StackMapTable: number_of_entries = 8
        frame_type = 255 /* full_frame */
          offset_delta = 24
          locals = [ class java/lang/String, class java/lang/String, class java/lang/String, class java/lang/String ]
          stack = [ class java/io/PrintStream ]
        frame_type = 255 /* full_frame */
          offset_delta = 0
          locals = [ class java/lang/String, class java/lang/String, class java/lang/String, class java/lang/String ]
          stack = [ class java/io/PrintStream, int ]
        frame_type = 255 /* full_frame */
          offset_delta = 36
          locals = [ class java/lang/String, class java/lang/String, class java/lang/String, class java/lang/String, class java/lang/String ]
          stack = [ class java/io/PrintStream ]
        frame_type = 255 /* full_frame */
          offset_delta = 0
          locals = [ class java/lang/String, class java/lang/String, class java/lang/String, class java/lang/String, class java/lang/String ]
          stack = [ class java/io/PrintStream, int ]
        frame_type = 255 /* full_frame */
          offset_delta = 35
          locals = [ class java/lang/String, class java/lang/String, class java/lang/String, class java/lang/String, class java/lang/String, class java/lang/String ]
          stack = [ class java/io/PrintStream ]
        frame_type = 255 /* full_frame */
          offset_delta = 0
          locals = [ class java/lang/String, class java/lang/String, class java/lang/String, class java/lang/String, class java/lang/String, class java/lang/String ]
          stack = [ class java/io/PrintStream, int ]
        frame_type = 80 /* same_locals_1_stack_item */
          stack = [ class java/io/PrintStream ]
        frame_type = 255 /* full_frame */
          offset_delta = 0
          locals = [ class java/lang/String, class java/lang/String, class java/lang/String, class java/lang/String, class java/lang/String, class java/lang/String ]
          stack = [ class java/io/PrintStream, int ]

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
    Code:
      stack=0, locals=1, args_size=1
         0: invokestatic  #27                 // Method testStringCreate:()V
         3: invokestatic  #28                 // Method testStringConcat:()V
         6: invokestatic  #29                 // Method testStringIntern:()V
         9: return
      LineNumberTable:
        line 82: 0
        line 83: 3
        line 84: 6
        line 86: 9
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      10     0  args   [Ljava/lang/String;

  public java.lang.String getCity();
    descriptor: ()Ljava/lang/String;
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: getfield      #30                 // Field city:Ljava/lang/String;
         4: areturn
      LineNumberTable:
        line 89: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/example/javaadvanced/jvm/ex2/Location;

  public void setCity(java.lang.String);
    descriptor: (Ljava/lang/String;)V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: aload_1
         2: putfield      #30                 // Field city:Ljava/lang/String;
         5: return
      LineNumberTable:
        line 93: 0
        line 94: 5
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       6     0  this   Lcom/example/javaadvanced/jvm/ex2/Location;
            0       6     1  city   Ljava/lang/String;

  public java.lang.String getRegion();
    descriptor: ()Ljava/lang/String;
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: getfield      #31                 // Field region:Ljava/lang/String;
         4: areturn
      LineNumberTable:
        line 97: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/example/javaadvanced/jvm/ex2/Location;

  public void setRegion(java.lang.String);
    descriptor: (Ljava/lang/String;)V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: aload_1
         2: putfield      #31                 // Field region:Ljava/lang/String;
         5: return
      LineNumberTable:
        line 101: 0
        line 102: 5
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       6     0  this   Lcom/example/javaadvanced/jvm/ex2/Location;
            0       6     1 region   Ljava/lang/String;
}
SourceFile: "Location.java"

常见面试题剖析

新生代为什么要分成eden,s0,s1三个区域,为什么不能分成两个区域,三个区域的比例是多少,为什么是这个比例

因为新生代使用的是复制算法,大部分对象都是朝生夕死的,如果只有两个区域,则会有50%的内存空间是浪费的,分为三个区域可以提高空间利用率,三个区域的比例是8:1:1,空间利用率由50%提高到90%

说一下JVM内存结构

开放式题目,具体可见章节 运行时数据区域
一般从两个维度出发:线程私有和线程共享。到每一个内存区域的细节点。
在这里插入图片描述

Java 虚拟机栈是基于线程的。哪怕你只有一个 main() 方法,也是以线程的方式运行的。在线程的生命周期中,参与计算的数据会频繁地入栈和出栈,栈的生命周期是和线程一样的。
栈里的每条数据,就是栈帧。在每个 Java 方法被调用的时候,都会创建一个栈帧,并入栈。一旦完成相应的调用,则出栈。所有的栈帧都出栈后,线程也就结束了。每个栈帧,都包含四个区域:局部变量表、操作数栈、动态连接、返回地址

本地方法栈是和虚拟机栈非常相似的一个区域,它服务的对象是 native 方法。

程序计数器是一块较小的内存空间,它的作用可以看作是当前线程所执行的字节码的行号指示器。

堆是 JVM 上最大的内存区域,我们申请的几乎所有的对象,都是在这里存储的。我们常说的垃圾回收,操作的对象就是堆。

方法区,这个区域存储的内容,包括:类的信息、常量池、方法数据、方法代码。

什么情况下内存栈溢出?

java.lang.StackOverflowError : 如果出现了可能会是无限递归。
java.lang.OutOfMemoryError:不断建立线程,JVM不断申请栈内存,当机器没有足够的栈内存时。

描述new一个对象的流程

在这里插入图片描述

Java对象会不会分配在栈中?

可以,如果这个对象不满足逃逸分析,即如果对象发生了逃逸,那么虚拟机在特定的情况下会走栈上分配。

如何判断一个对象是否应该被回收,有哪些算法,实际虚拟机使用得最多的是什么?

引用计数法和根可达性分析两种,用得最多是根可达性分析。

GC收集算法有哪些?他们的特点是什么?

复制算法、标记清除算法、标记整理算法。
复制算法速度快,不会产生内存碎片,但是要浪费内存空间。
标记清除算法空间利用率高,不需要移动对象,但是有内存碎片产生。
标记整理算法没有产生内存碎片,但是要移动对象,性能较低。
三种算法各有所长,各有所短。

JVM中一次完整的GC流程是怎样的?对象如何晋级到老年代?

对象优先在新生代区中分配,若没有足够空间,Minor GC;
大对象(需要大量连续内存空间)直接进入老年态;长期存活的对象进入老年态。
如果对象在新生代出生并经过第一次MGC后仍然存活,年龄+1,若年龄超过一定限制(15),则被晋升到老年态。

Java中的几种引用关系,他们的区别是什么?

强引用
一般的Object obj = new Object() ,就属于强引用。在任何情况下,只有有强引用关联(与根可达)还在,垃圾回收器就永远不会回收掉被引用的对象。
软引用 SoftReference
一些有用但是并非必需,用软引用关联的对象,系统将要发生内存溢出(OuyOfMemory)之前,这些对象就会被回收(如果这次回收后还是没有足够的空间,才会抛出内存溢出)。
弱引用 WeakReference
一些有用(程度比软引用更低)但是并非必需,用弱引用关联的对象,只能生存到下一次垃圾回收之前,GC发生时,不管内存够不够,都会被回收。
虚引用 PhantomReference
幽灵引用,最弱(随时会被回收掉)
对象被垃圾回收的时候收到一个通知。

final、finally、finalize的区别?

final
在java中,final可以用来修饰类,方法和变量(成员变量或局部变量)
当用final修饰类的时,表明该类不能被其他类所继承。当我们需要让一个类永远不被继承,此时就可以用final修饰,但要注意:
final类中所有的成员方法都会隐式的定义为final方法。
使用final方法的原因主要有两个:
  (1) 把方法锁定,以防止继承类对其进行更改。
  (2) 效率,在早期的java版本中,会将final方法转为内嵌调用。但若方法过于庞大,可能在性能上不会有多大提升。因此在最近版本中,不需要final方法进行这些优化了。
final成员变量表示常量,只能被赋值一次,赋值后其值不再改变。

finally
finally作为异常处理的一部分,它只能用在try/catch语句中,并且附带一个语句块,表示这段语句最终一定会被执行(不管有没有抛出异常),经常被用在需要释放资源的情况下

finalize
Object中的Finalize()方法:即使通过可达性分析判断不可达的对象,也不是“非死不可”,它还会处于“缓刑”阶段,真正要宣告一个对象死亡,需要经过两次标记过程,一次是没有找到与GCRoots的引用链,它将被第一次标记。随后进行一次筛选(如果对象覆盖了finalize),我们可以在finalize中去拯救。
所以建议大家尽量不要使用finalize,因为这个方法太不可靠。在生产中你很难控制方法的执行或者对象的调用顺序,建议大家忘了finalize方法!因为在finalize方法能做的工作,java中有更好的,比如try-finally或者其他方式可以做得更好。

String s = new String(“xxx”);创建了几个对象?

2个:
1、在一开始字符串"xxx"会在加载类时,在常量池中创建一个字符串对象。
2、调用 new时 会在堆内存中创建一个 String 对象,String 对象中的 char 数组将会引用常量池中的字符串对象。

猜你喜欢

转载自blog.csdn.net/yzpbright/article/details/108154982
今日推荐