JVM - 结合代码示例彻底搞懂Java内存区域_对象在堆-栈-方法区(元空间)之间的关系
文章目錄
- Pre
- 示例demo
- 總體關系
- 代碼示例論證
- 反匯編
Pre
JVM - 結合代碼示例徹底搞懂Java內存區域_線程棧 | 本地方法棧 | 程序計數器
中我們探討了線程棧中的內部結構 ,大家有么有想過main方法呢? 我們繼續來看下main方法
示例demo
package com.gof.test;public class Artisan {public static final int FIVE = 5 ; // final靜態變public static User user = new User();// 靜態變量public static void main(String[] args) {Artisan artisan = new Artisan();artisan.doSomething();}public int doSomething() {int a = 1 ;int b = 2 ;int c = (a + b) * 10 ;return c;} }final對象和static對象 ,我們知道都會存放在方法區(元空間)中的運行時常量池。 User 和 FIVE 會存放在該區域內。
方法區#運行時常量池 ,是方法區的一部分。 Class文件中的常量池表用于存放編譯期間生成的各種字面量和符號引用,這部分內容將在類加載后放到方法區的運行時常量池中。
反匯編 ,附帶附件信息
E:\Program Files\Java\jdk1.8.0_161\bin> ./javap -c -v D:\IdeaProjects\GOF23\target\classes\com\gof\test\Artisan.class > Artisan.txt PS E:\Program Files\Java\jdk1.8.0_161\bin>可以看到 Constant Pool
Constant pool:#1 = Methodref #8.#35 // java/lang/Object."<init>":()V#2 = Class #36 // com/gof/test/Artisan#3 = Methodref #2.#35 // com/gof/test/Artisan."<init>":()V#4 = Methodref #2.#37 // com/gof/test/Artisan.doSomething:()I#5 = Class #38 // com/gof/test/User#6 = Methodref #5.#35 // com/gof/test/User."<init>":()V#7 = Fieldref #2.#39 // com/gof/test/Artisan.user:Lcom/gof/test/User;#8 = Class #40 // java/lang/Object#9 = Utf8 FIVE#10 = Utf8 I#11 = Utf8 ConstantValue#12 = Integer 5#13 = Utf8 user#14 = Utf8 Lcom/gof/test/User;#15 = Utf8 <init>#16 = Utf8 ()V#17 = Utf8 Code#18 = Utf8 LineNumberTable#19 = Utf8 LocalVariableTable#20 = Utf8 this#21 = Utf8 Lcom/gof/test/Artisan;#22 = Utf8 main#23 = Utf8 ([Ljava/lang/String;)V#24 = Utf8 args#25 = Utf8 [Ljava/lang/String;#26 = Utf8 artisan#27 = Utf8 doSomething#28 = Utf8 ()I#29 = Utf8 a#30 = Utf8 b#31 = Utf8 c#32 = Utf8 <clinit>#33 = Utf8 SourceFile#34 = Utf8 Artisan.java#35 = NameAndType #15:#16 // "<init>":()V#36 = Utf8 com/gof/test/Artisan#37 = NameAndType #27:#28 // doSomething:()I#38 = Utf8 com/gof/test/User#39 = NameAndType #13:#14 // user:Lcom/gof/test/User;#40 = Utf8 java/lang/Object找下User和 FIVE
總體關系
Note: FIVE 是 final的,上圖少寫了
代碼示例論證
當我們執行main方法
public static void main(String[] args) {Artisan artisan = new Artisan();artisan.doSomething();}Artisan artisan = new Artisan(); 這個對象會在堆上分配一塊內存空間用來存儲該對象。
main也是個方法,也得有方法棧, 那方法棧中的局部變量表中存放的artisan是個啥呢? 其實是 對象的引用 ,也就是對象的內存地址 。
這樣,線程棧和堆的關系就產生了。
當類在編譯階段,靜態類User , 會被分配到方法區 , 那 new User() 存放在 堆中,方法區的User 和 堆中的User 什么關系呢? 引用的關系,方法區中的User僅僅是個符號引用,指向真正的堆內存中的User對象。
這樣 方法區和堆的關系就產生了 。
反匯編
Classfile /D:/IdeaProjects/GOF23/target/classes/com/gof/test/Artisan.classLast modified 2020-6-22; size 772 bytesMD5 checksum 89d38013e132ab14203f796617191dd9Compiled from "Artisan.java" public class com.gof.test.Artisanminor version: 0major version: 52flags: ACC_PUBLIC, ACC_SUPER Constant pool:#1 = Methodref #8.#35 // java/lang/Object."<init>":()V#2 = Class #36 // com/gof/test/Artisan#3 = Methodref #2.#35 // com/gof/test/Artisan."<init>":()V#4 = Methodref #2.#37 // com/gof/test/Artisan.doSomething:()I#5 = Class #38 // com/gof/test/User#6 = Methodref #5.#35 // com/gof/test/User."<init>":()V#7 = Fieldref #2.#39 // com/gof/test/Artisan.user:Lcom/gof/test/User;#8 = Class #40 // java/lang/Object#9 = Utf8 FIVE#10 = Utf8 I#11 = Utf8 ConstantValue#12 = Integer 5#13 = Utf8 user#14 = Utf8 Lcom/gof/test/User;#15 = Utf8 <init>#16 = Utf8 ()V#17 = Utf8 Code#18 = Utf8 LineNumberTable#19 = Utf8 LocalVariableTable#20 = Utf8 this#21 = Utf8 Lcom/gof/test/Artisan;#22 = Utf8 main#23 = Utf8 ([Ljava/lang/String;)V#24 = Utf8 args#25 = Utf8 [Ljava/lang/String;#26 = Utf8 artisan#27 = Utf8 doSomething#28 = Utf8 ()I#29 = Utf8 a#30 = Utf8 b#31 = Utf8 c#32 = Utf8 <clinit>#33 = Utf8 SourceFile#34 = Utf8 Artisan.java#35 = NameAndType #15:#16 // "<init>":()V#36 = Utf8 com/gof/test/Artisan#37 = NameAndType #27:#28 // doSomething:()I#38 = Utf8 com/gof/test/User#39 = NameAndType #13:#14 // user:Lcom/gof/test/User;#40 = Utf8 java/lang/Object {public static final int FIVE;descriptor: Iflags: ACC_PUBLIC, ACC_STATIC, ACC_FINALConstantValue: int 5public static com.gof.test.User user;descriptor: Lcom/gof/test/User;flags: ACC_PUBLIC, ACC_STATICpublic com.gof.test.Artisan();descriptor: ()Vflags: ACC_PUBLICCode:stack=1, locals=1, args_size=10: aload_01: invokespecial #1 // Method java/lang/Object."<init>":()V4: returnLineNumberTable:line 4: 0LocalVariableTable:Start Length Slot Name Signature0 5 0 this Lcom/gof/test/Artisan;public static void main(java.lang.String[]);descriptor: ([Ljava/lang/String;)Vflags: ACC_PUBLIC, ACC_STATICCode:stack=2, locals=2, args_size=10: new #2 // class com/gof/test/Artisan3: dup4: invokespecial #3 // Method "<init>":()V7: astore_18: aload_19: invokevirtual #4 // Method doSomething:()I12: pop13: returnLineNumberTable:line 9: 0line 10: 8line 11: 13LocalVariableTable:Start Length Slot Name Signature0 14 0 args [Ljava/lang/String;8 6 1 artisan Lcom/gof/test/Artisan;public int doSomething();descriptor: ()Iflags: 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 13: 0line 14: 2line 15: 4line 16: 11LocalVariableTable:Start Length Slot Name Signature0 13 0 this Lcom/gof/test/Artisan;2 11 1 a I4 9 2 b I11 2 3 c Istatic {};descriptor: ()Vflags: ACC_STATICCode:stack=2, locals=0, args_size=00: new #5 // class com/gof/test/User3: dup4: invokespecial #6 // Method com/gof/test/User."<init>":()V7: putstatic #7 // Field user:Lcom/gof/test/User;10: returnLineNumberTable:line 6: 0 } SourceFile: "Artisan.java" 《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的JVM - 结合代码示例彻底搞懂Java内存区域_对象在堆-栈-方法区(元空间)之间的关系的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JVM - 结合代码示例彻底搞懂Java
- 下一篇: JVM - 应用JVM核心参数推荐设置