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 2020年8月20日; size 731 bytesSHA-256 checksum 326bd51b63d835ab4e480d26c8345b11db4d260c0da6a5a8770f3f6ca2867e28Compiled from "Person.java"
public class com.example.javaadvanced.jvm.ex1.Personminor version: 0major version: 51flags: (0x0021) ACC_PUBLIC, ACC_SUPERthis_class: #2 // com/example/javaadvanced/jvm/ex1/Personsuper_class: #6 // java/lang/Objectinterfaces: 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: ()Vflags: (0x0001) ACC_PUBLICCode:stack=1, locals=1, args_size=10: aload_01: invokespecial #1 // Method java/lang/Object."<init>":()V4: returnLineNumberTable:line 7: 0LocalVariableTable:Start Length Slot Name Signature0 5 0 this Lcom/example/javaadvanced/jvm/ex1/Person;public int work() throws java.lang.Exception;descriptor: ()Iflags: (0x0001) ACC_PUBLICCode:stack=2, locals=4, args_size=10: iconst_11: istore_12: iconst_23: istore_24: iload_15: iload_26: iadd7: bipush 109: imul10: istore_311: iload_312: ireturnLineNumberTable:line 10: 0line 11: 2line 12: 4line 13: 11LocalVariableTable:Start Length Slot Name Signature0 13 0 this Lcom/example/javaadvanced/jvm/ex1/Person;2 11 1 x I4 9 2 y I11 2 3 z IExceptions:throws java.lang.Exceptionpublic static void main(java.lang.String[]) throws java.lang.Exception;descriptor: ([Ljava/lang/String;)Vflags: (0x0009) ACC_PUBLIC, ACC_STATICCode:stack=2, locals=3, args_size=10: new #2 // class com/example/javaadvanced/jvm/ex1/Person3: dup4: invokespecial #3 // Method "<init>":()V7: astore_18: aload_19: invokevirtual #4 // Method work:()I12: pop13: aload_114: invokevirtual #5 // Method java/lang/Object.hashCode:()I17: pop18: bipush 1220: istore_221: returnLineNumberTable:line 17: 0line 18: 8line 19: 13line 20: 18line 21: 21LocalVariableTable:Start Length Slot Name Signature0 22 0 args [Ljava/lang/String;8 14 1 person Lcom/example/javaadvanced/jvm/ex1/Person;21 1 2 i IExceptions: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"加入常量池中,并返回该字符串的引用4String 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);//falseString hello3 = hel + lo;System.out.println(hello == hello3);//falseSystem.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 2020年8月21日; size 2265 bytesSHA-256 checksum 177a9cc73d0d275d8f200e7104d1b12c6e404d32d7d52bee8f5095134225db58Compiled from "Location.java"
public class com.example.javaadvanced.jvm.ex2.Locationminor version: 0major version: 51flags: (0x0021) ACC_PUBLIC, ACC_SUPERthis_class: #2 // com/example/javaadvanced/jvm/ex2/Locationsuper_class: #32 // java/lang/Objectinterfaces: 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: ()Vflags: (0x0001) ACC_PUBLICCode:stack=1, locals=1, args_size=10: aload_01: invokespecial #1 // Method java/lang/Object."<init>":()V4: returnLineNumberTable:line 3: 0LocalVariableTable:Start Length Slot Name Signature0 5 0 this Lcom/example/javaadvanced/jvm/ex2/Location;public static void testStringCreate();descriptor: ()Vflags: (0x0009) ACC_PUBLIC, ACC_STATICCode:stack=3, locals=3, args_size=00: new #2 // class com/example/javaadvanced/jvm/ex2/Location3: dup4: invokespecial #3 // Method "<init>":()V7: astore_08: aload_09: ldc #4 // String 深圳11: invokevirtual #5 // Method setCity:(Ljava/lang/String;)V14: aload_015: ldc #6 // String 南山17: invokevirtual #7 // Method setRegion:(Ljava/lang/String;)V20: ldc #8 // String abc22: astore_123: new #9 // class java/lang/String26: dup27: ldc #10 // String abcd29: invokespecial #11 // Method java/lang/String."<init>":(Ljava/lang/String;)V32: astore_233: returnLineNumberTable:line 11: 0line 12: 8line 13: 14line 17: 20line 23: 23line 26: 33LocalVariableTable:Start Length Slot Name Signature8 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: ()Vflags: (0x0009) ACC_PUBLIC, ACC_STATICCode:stack=3, locals=2, args_size=00: new #9 // class java/lang/String3: dup4: ldc #12 // String king6: invokespecial #11 // Method java/lang/String."<init>":(Ljava/lang/String;)V9: invokevirtual #13 // Method java/lang/String.intern:()Ljava/lang/String;12: astore_013: new #9 // class java/lang/String16: dup17: ldc #12 // String king19: invokespecial #11 // Method java/lang/String."<init>":(Ljava/lang/String;)V22: invokevirtual #13 // Method java/lang/String.intern:()Ljava/lang/String;25: astore_126: aload_027: aload_128: if_acmpne 4231: getstatic #14 // Field java/lang/System.out:Ljava/io/PrintStream;34: ldc #15 // String a==b36: invokevirtual #16 // Method java/io/PrintStream.println:(Ljava/lang/String;)V39: goto 5042: getstatic #14 // Field java/lang/System.out:Ljava/io/PrintStream;45: ldc #17 // String a!=b47: invokevirtual #16 // Method java/io/PrintStream.println:(Ljava/lang/String;)V50: returnLineNumberTable:line 36: 0line 41: 13line 43: 26line 44: 31line 46: 42line 49: 50LocalVariableTable:Start Length Slot Name Signature13 38 0 a Ljava/lang/String;26 25 1 b Ljava/lang/String;StackMapTable: number_of_entries = 2frame_type = 253 /* append */offset_delta = 42locals = [ class java/lang/String, class java/lang/String ]frame_type = 7 /* same */public static void testStringConcat();descriptor: ()Vflags: (0x0009) ACC_PUBLIC, ACC_STATICCode:stack=3, locals=7, args_size=00: ldc #18 // String hello2: astore_03: ldc #19 // String hel5: astore_16: ldc #20 // String lo8: astore_29: ldc #18 // String hello11: astore_312: getstatic #14 // Field java/lang/System.out:Ljava/io/PrintStream;15: aload_016: aload_317: if_acmpne 2420: iconst_121: goto 2524: iconst_025: invokevirtual #21 // Method java/io/PrintStream.println:(Z)V28: new #22 // class java/lang/StringBuilder31: dup32: invokespecial #23 // Method java/lang/StringBuilder."<init>":()V35: ldc #19 // String hel37: invokevirtual #24 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;40: aload_241: 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 449: getstatic #14 // Field java/lang/System.out:Ljava/io/PrintStream;52: aload_053: aload 455: if_acmpne 6258: iconst_159: goto 6362: iconst_063: invokevirtual #21 // Method java/io/PrintStream.println:(Z)V66: new #22 // class java/lang/StringBuilder69: dup70: invokespecial #23 // Method java/lang/StringBuilder."<init>":()V73: aload_174: invokevirtual #24 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;77: aload_278: 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 586: getstatic #14 // Field java/lang/System.out:Ljava/io/PrintStream;89: aload_090: aload 592: if_acmpne 9995: iconst_196: goto 10099: iconst_0100: invokevirtual #21 // Method java/io/PrintStream.println:(Z)V103: getstatic #14 // Field java/lang/System.out:Ljava/io/PrintStream;106: aload 4108: aload 5110: if_acmpne 117113: iconst_1114: goto 118117: iconst_0118: invokevirtual #21 // Method java/io/PrintStream.println:(Z)V121: ldc #26 // String appleorange123: astore 6125: returnLineNumberTable:line 58: 0line 59: 3line 60: 6line 64: 9line 65: 12line 68: 28line 69: 49line 71: 66line 72: 86line 73: 103line 76: 121line 77: 125LocalVariableTable:Start Length Slot Name Signature3 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 = 8frame_type = 255 /* full_frame */offset_delta = 24locals = [ 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 = 0locals = [ 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 = 36locals = [ 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 = 0locals = [ 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 = 35locals = [ 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 = 0locals = [ 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 = 0locals = [ 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;)Vflags: (0x0009) ACC_PUBLIC, ACC_STATICCode:stack=0, locals=1, args_size=10: invokestatic #27 // Method testStringCreate:()V3: invokestatic #28 // Method testStringConcat:()V6: invokestatic #29 // Method testStringIntern:()V9: returnLineNumberTable:line 82: 0line 83: 3line 84: 6line 86: 9LocalVariableTable:Start Length Slot Name Signature0 10 0 args [Ljava/lang/String;public java.lang.String getCity();descriptor: ()Ljava/lang/String;flags: (0x0001) ACC_PUBLICCode:stack=1, locals=1, args_size=10: aload_01: getfield #30 // Field city:Ljava/lang/String;4: areturnLineNumberTable:line 89: 0LocalVariableTable:Start Length Slot Name Signature0 5 0 this Lcom/example/javaadvanced/jvm/ex2/Location;public void setCity(java.lang.String);descriptor: (Ljava/lang/String;)Vflags: (0x0001) ACC_PUBLICCode:stack=2, locals=2, args_size=20: aload_01: aload_12: putfield #30 // Field city:Ljava/lang/String;5: returnLineNumberTable:line 93: 0line 94: 5LocalVariableTable:Start Length Slot Name Signature0 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_PUBLICCode:stack=1, locals=1, args_size=10: aload_01: getfield #31 // Field region:Ljava/lang/String;4: areturnLineNumberTable:line 97: 0LocalVariableTable:Start Length Slot Name Signature0 5 0 this Lcom/example/javaadvanced/jvm/ex2/Location;public void setRegion(java.lang.String);descriptor: (Ljava/lang/String;)Vflags: (0x0001) ACC_PUBLICCode:stack=2, locals=2, args_size=20: aload_01: aload_12: putfield #31 // Field region:Ljava/lang/String;5: returnLineNumberTable:line 101: 0line 102: 5LocalVariableTable:Start Length Slot Name Signature0 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 数组将会引用常量池中的字符串对象。
Java进阶之深入理解对象与垃圾回收机制常见面试题相关推荐
- 【33】深入理解对象与垃圾回收机制
(1)一个人只要自己不放弃自己,整个世界也不会放弃你. (2)天生我才必有大用 (3)不能忍受学习之苦就一定要忍受生活之苦,这是多么痛苦而深刻的领悟. (4)做难事必有所得 (5)精神乃真正的刀锋 ( ...
- jvm垃圾回收机制_深入理解JVM的垃圾回收机制
如何判断对象已"死" Java堆中存放着几乎所有的对象实例,垃圾回收器在堆进行垃圾回收前,首先要判断这些对象那些还存活,那些已经"死去".判断对象是否已&qu ...
- Java工程师必备:JVM原理、内存模型、调优、垃圾回收机制、面试题
在如今这个时间和知识都是碎片化的时代,C站根据C1-C4认证的成长路径,进行知识细化整理,形成系统化的知识图谱. 通过调研一线互联网大厂的招聘JD,小编对标C站能力认证要求,为大家整理了系列技术干货合 ...
- C++对象实现原理(附常见面试题)
C++对象实现原理(附常见面试题) 内存排布 最简单的类 带有非虚函数的类 带有虚函数的类 继承和成员对象 多重继承 虚继承 对象的构造 构造函数的隐藏工作 初始化列表 对象的析构 常见面试题 结语 ...
- 【JAVA进阶】JVM第二篇- JVM 垃圾回收详解
写在前面的话 脑子是个好东西,可惜的是一直没有搞懂脑子的内存删除机制是什么,所以啊,入行多年,零零散散的文章看了无数,却总是学习了很多也忘了很多. 痛定思痛的我决定从今天开始系统的梳理下知识架构,记录 ...
- Java面试官最爱问的垃圾回收机制,mysql密码忘记
一.硬核! 30张图解HTTP常见面试题 在面试过程中.HTTP被提问的概率还是比较高的. 小编我授集了5大类HTTP面试常问的题目,同时这5大类题跟HTTP的发展和演变关联性是比较大的,通过问答+图 ...
- 【JAVA秒会技术之秒杀面试官】JavaEE常见面试题(六)
[前言]别人都在你看不到的地方暗自努力,在你看得到的地方,他们也和你一样显得游手好闲,和你一样会抱怨,而只有你自己相信这些都是真的,最后,也只有你一个人继续不思进取 -- [下载]个人结合诸多资料 ...
- 【JAVA秒会技术之秒杀面试官】JavaSE常见面试题(二)
21.在Java中,如何跳出当前的多重嵌套循环? 答:在最外层循环前加一个标记如A,然后用break A;可以跳出多重循环.(Java中支持带标签的break和continue语句,作用有点类似于C和 ...
- java ee笔试题_【JAVA秒会技术之秒杀面试官】JavaEE常见面试题(六)
[前言]别人都在你看不到的地方暗自努力,在你看得到的地方,他们也和你一样显得游手好闲,和你一样会抱怨,而只有你自己相信这些都是真的,最后,也只有你一个人继续不思进取 -- [下载]个人结合诸多资料,总 ...
最新文章
- 1.14 实例:完善除法运算的错误信息
- matlab中m文件的作用,M文件主要包含()_matlab中m文件的好处
- 【吐血整理】年度盘点 | 2019年Java面试题汇总篇——附答案
- (软件工程复习核心重点)第六章实现和测试-第八节:调试
- 推荐系统在滴滴司机调度系统中的应用实践
- mysql5.7 解压版 中文乱码_MySQL 5.7解压版安装、卸载及乱码问题的图文解决方法...
- cgblib 代理接口原理_Spring5参考指南-AOP代理
- 【Flutter】基础组件【06】Image
- 牛客小白月赛24 D.牛妹吃豆子
- 中心矩和原点矩_中心矩和原点矩的几何意义是什么呢,无法理解
- 物质、分子、原子、原子核、中子、质子、电子、量子、离子的区别
- 【Win8自带微软输入法删除图解】
- Q1营收增长66%,Snap继续靠“广告业务”发家能长期利好么?
- #displaytag:一个简易的Java分页插件(无需其他的前端分页插件) @FDDLC
- 公司小白熟悉苹果Mac常用简单操作
- 洛谷 P1948 / loj 10074 / 一本通 1496【分层图】
- 瑞星wifi二代来袭,wifi,U盘两用
- 线性代数(五)向量空间——向量空间的基 维数 内积 基的规范正交化
- Individual tree segmentation and tree-counting using supervised clustering
- 商汤科技创业资源及来源分析思维导图
热门文章
- 用户登录注册流程图-所有项目论文通用计算机毕业设计
- [转载]Eclipse开发工具简介
- rds proxy 数据库代理 简介
- 360手机java手机管家软件_360手机管家最新版下载_360手机管家官方下载-太平洋下载中心...
- crmeb 易联云k4小票打印机相关配置说明
- 将文件转换为Base64格式
- Excel数据分析常用函数①——查询函数(vlookup,hlookup,lookup,match,index…)
- python怎样使用各个日期赤纬_Python-PyEphem方位和高度计算
- 【数据分析】指标体系
- DBMS/Database:数据库管理的简介、安装(注意事项等)、学习路线(基于SQLSever深入理解SQL命令语句综合篇《初级→中级→高级》/几十项代码案例集合)之详细攻略