堆:new 出的對象在堆上
java棧:java程序、線程運行數據、內存數據
每個方法都有自己的棧、運行時需要的數據存在自己的棧中
每個線程對立的是圖中淺藍色的部分(java棧、本地方法棧、程序計數器)
堆和方法區是所有線程共享的
java棧會對調用的每個方法生成一個棧幀
編寫一個簡單的Math.java 文件
package com.example.demo; public class Math { public static final Integer CONSTANT_1 = 666; public int math() { int a = 1; int b = 2; int c = (a + b) * 10; return c; } public static void main(String[] args) { Math math = new Math(); System.out.println(math.math()); System.out.println("end"); } }
Math.class
cafe babe 0000 0034 0030 0a00 0b00 1907 001a 0a00 0200 1909 001b 001c 0a00 0200 1d0a 001e 001f 0800 200a 001e 0021 0a00 2200 2309 0002 0024 0700 2501 000a 434f 4e53 5441 4e54 5f31 0100 134c 6a61 7661 2f6c 616e 672f 496e 7465 6765 723b 0100 063c 696e 6974 3e01 0003 2829 5601 0004 436f 6465 0100 0f4c 696e 654e 756d 6265 7254 6162 6c65 0100 046d 6174 6801 0003 2829 4901 0004 6d61 696e 0100 1628 5b4c 6a61 7661 2f6c 616e 672f 5374 7269 6e67 3b29 5601 0008 3c63 6c69 6e69 743e 0100 0a53 6f75 7263 6546 696c 6501 0009 4d61 7468 2e6a 6176 610c 000e 000f 0100 1563 6f6d 2f65 7861 6d70 6c65 2f64 656d 6f2f 4d61 7468 0700 260c 0027 0028 0c00 1200 1307 0029 0c00 2a00 2b01 0003 656e 640c 002a 002c 0700 2d0c 002e 002f 0c00 0c00 0d01 0010 6a61 7661 2f6c 616e 672f 4f62 6a65 6374 0100 106a 6176 612f 6c61 6e67 2f53 7973 7465 6d01 0003 6f75 7401 0015 4c6a 6176 612f 696f 2f50 7269 6e74 5374 7265 616d 3b01 0013 6a61 7661 2f69 6f2f 5072 696e 7453 7472 6561 6d01 0007 7072 696e 746c 6e01 0004 2849 2956 0100 1528 4c6a 6176 612f 6c61 6e67 2f53 7472 696e 673b 2956 0100 116a 6176 612f 6c61 6e67 2f49 6e74 6567 6572 0100 0776 616c 7565 4f66 0100 1628 4929 4c6a 6176 612f 6c61 6e67 2f49 6e74 6567 6572 3b00 2100 0200 0b00 0000 0100 1900 0c00 0d00 0000 0400 0100 0e00 0f00 0100 1000 0000 1d00 0100 0100 0000 052a b700 01b1 0000 0001 0011 0000 0006 0001 0000 0003 0001 0012 0013 0001 0010 0000 0031 0002 0004 0000 000d 043c 053d 1b1c 6010 0a68 3e1d ac00 0000 0100 1100 0000 1200 0400 0000 0700 0200 0800 0400 0900 0b00 0a00 0900 1400 1500 0100 1000 0000 3f00 0200 0200 0000 1bbb 0002 59b7 0003 4cb2 0004 2bb6 0005 b600 06b2 0004 1207 b600 08b1 0000 0001 0011 0000 0012 0004 0000 000e 0008 000f 0012 0010 001a 0011 0008 0016 000f 0001 0010 0000 0022 0001 0000 0000 000a 1102 9ab8 0009 b300 0ab1 0000 0001 0011 0000 0006 0001 0000 0004 0001 0017 0000 0002 0018
利用java命令
javap -c Maht.txt
對應的字節碼
Compiled from "Math.java" public class com.example.demo.Math { public static final java.lang.Integer CONSTANT_1; public com.example.demo.Math(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return public int math(); Code: 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 public static void main(java.lang.String[]); Code: 0: new #2 // class com/example/demo/Math 3: dup 4: invokespecial #3 // Method "<init>":()V 7: astore_1 8: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream; 11: aload_1 12: invokevirtual #5 // Method math:()I 15: invokevirtual #6 // Method java/io/PrintStream.println:(I)V 18: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream; 21: ldc #7 // String end 23: invokevirtual #8 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 26: return static {}; Code: 0: sipush 666 3: invokestatic #9 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 6: putstatic #10 // Field CONSTANT_1:Ljava/lang/Integer; 9: return }
jvm指令集
跳轉到class文件目錄,使用 javap -c StringTest.class -> p.txt 1 命令將編譯后的文件輸出到p.txt文件 棧和局部變量操作 將常量壓入棧的指令 aconst_null 將null對象引用壓入棧 iconst_m1 將int類型常量-1壓入棧 iconst_0 將int類型常量0壓入棧 iconst_1 將int類型常量1壓入棧 iconst_2 將int類型常量2壓入棧 iconst_3 將int類型常量3壓入棧 iconst_4 將int類型常量4壓入棧 iconst_5 將int類型常量5壓入棧 lconst_0 將long類型常量0壓入棧 lconst_1 將long類型常量1壓入棧 fconst_0 將float類型常量0壓入棧 fconst_1 將float類型常量1壓入棧 dconst_0 將double類型常量0壓入棧 dconst_1 將double類型常量1壓入棧 bipush 將一個8位帶符號整數壓入棧 sipush 將16位帶符號整數壓入棧 ldc 把常量池中的項壓入棧 ldc_w 把常量池中的項壓入棧(使用寬索引) ldc2_w 把常量池中long類型或者double類型的項壓入棧(使用寬索引) 從棧中的局部變量中裝載值的指令 iload 從局部變量中裝載int類型值 lload 從局部變量中裝載long類型值 fload 從局部變量中裝載float類型值 dload 從局部變量中裝載double類型值 aload 從局部變量中裝載引用類型值(refernce) iload_0 從局部變量0中裝載int類型值 iload_1 從局部變量1中裝載int類型值 iload_2 從局部變量2中裝載int類型值 iload_3 從局部變量3中裝載int類型值 lload_0 從局部變量0中裝載long類型值 lload_1 從局部變量1中裝載long類型值 lload_2 從局部變量2中裝載long類型值 lload_3 從局部變量3中裝載long類型值 fload_0 從局部變量0中裝載float類型值 fload_1 從局部變量1中裝載float類型值 fload_2 從局部變量2中裝載float類型值 fload_3 從局部變量3中裝載float類型值 dload_0 從局部變量0中裝載double類型值 dload_1 從局部變量1中裝載double類型值 dload_2 從局部變量2中裝載double類型值 dload_3 從局部變量3中裝載double類型值 aload_0 從局部變量0中裝載引用類型值 aload_1 從局部變量1中裝載引用類型值 aload_2 從局部變量2中裝載引用類型值 aload_3 從局部變量3中裝載引用類型值 iaload 從數組中裝載int類型值 laload 從數組中裝載long類型值 faload 從數組中裝載float類型值 daload 從數組中裝載double類型值 aaload 從數組中裝載引用類型值 baload 從數組中裝載byte類型或boolean類型值 caload 從數組中裝載char類型值 saload 從數組中裝載short類型值 將棧中的值存入局部變量的指令 istore 將int類型值存入局部變量 lstore 將long類型值存入局部變量 fstore 將float類型值存入局部變量 dstore 將double類型值存入局部變量 astore 將將引用類型或returnAddress類型值存入局部變量 istore_0 將int類型值存入局部變量0 istore_1 將int類型值存入局部變量1 istore_2 將int類型值存入局部變量2 istore_3 將int類型值存入局部變量3 lstore_0 將long類型值存入局部變量0 lstore_1 將long類型值存入局部變量1 lstore_2 將long類型值存入局部變量2 lstore_3 將long類型值存入局部變量3 fstore_0 將float類型值存入局部變量0 fstore_1 將float類型值存入局部變量1 fstore_2 將float類型值存入局部變量2 fstore_3 將float類型值存入局部變量3 dstore_0 將double類型值存入局部變量0 dstore_1 將double類型值存入局部變量1 dstore_2 將double類型值存入局部變量2 dstore_3 將double類型值存入局部變量3 astore_0 將引用類型或returnAddress類型值存入局部變量0 astore_1 將引用類型或returnAddress類型值存入局部變量1 astore_2 將引用類型或returnAddress類型值存入局部變量2 astore_3 將引用類型或returnAddress類型值存入局部變量3 iastore 將int類型值存入數組中 lastore 將long類型值存入數組中 fastore 將float類型值存入數組中 dastore 將double類型值存入數組中 aastore 將引用類型值存入數組中 bastore 將byte類型或者boolean類型值存入數組中 castore 將char類型值存入數組中 sastore 將short類型值存入數組中 wide指令 wide 使用附加字節擴展局部變量索引 通用(無類型)棧操作 nop 不做任何操作 pop 彈出棧頂端一個字長的內容 pop2 彈出棧頂端兩個字長的內容 dup 復制棧頂部一個字長內容 dup_x1 復制棧頂部一個字長的內容,然后將復制內容及原來彈出的兩個字長的內容壓入棧 dup_x2 復制棧頂部一個字長的內容,然后將復制內容及原來彈出的三個字長的內容壓入棧 dup2 復制棧頂部兩個字長內容 dup2_x1 復制棧頂部兩個字長的內容,然后將復制內容及原來彈出的三個字長的內容壓入棧 dup2_x2 復制棧頂部兩個字長的內容,然后將復制內容及原來彈出的四個字長的內容壓入棧 swap 交換棧頂部兩個字長內容 類型轉換 i2l 把int類型的數據轉化為long類型 i2f 把int類型的數據轉化為float類型 i2d 把int類型的數據轉化為double類型 l2i 把long類型的數據轉化為int類型 l2f 把long類型的數據轉化為float類型 l2d 把long類型的數據轉化為double類型 f2i 把float類型的數據轉化為int類型 f2l 把float類型的數據轉化為long類型 f2d 把float類型的數據轉化為double類型 d2i 把double類型的數據轉化為int類型 d2l 把double類型的數據轉化為long類型 d2f 把double類型的數據轉化為float類型 i2b 把int類型的數據轉化為byte類型 i2c 把int類型的數據轉化為char類型 i2s 把int類型的數據轉化為short類型 整數運算 iadd 執行int類型的加法 ladd 執行long類型的加法 isub 執行int類型的減法 lsub 執行long類型的減法 imul 執行int類型的乘法 lmul 執行long類型的乘法 idiv 執行int類型的除法 ldiv 執行long類型的除法 irem 計算int類型除法的余數 lrem 計算long類型除法的余數 ineg 對一個int類型值進行取反操作 lneg 對一個long類型值進行取反操作 iinc 把一個常量值加到一個int類型的局部變量上 邏輯運算 移位操作 ishl 執行int類型的向左移位操作 lshl 執行long類型的向左移位操作 ishr 執行int類型的向右移位操作 lshr 執行long類型的向右移位操作 iushr 執行int類型的向右邏輯移位操作 lushr 執行long類型的向右邏輯移位操作 按位布爾運算 iand 對int類型值進行“邏輯與”操作 land 對long類型值進行“邏輯與”操作 ior 對int類型值進行“邏輯或”操作 lor 對long類型值進行“邏輯或”操作 ixor 對int類型值進行“邏輯異或”操作 lxor 對long類型值進行“邏輯異或”操作 浮點運算 fadd 執行float類型的加法 dadd 執行double類型的加法 fsub 執行float類型的減法 dsub 執行double類型的減法 fmul 執行float類型的乘法 dmul 執行double類型的乘法 fdiv 執行float類型的除法 ddiv 執行double類型的除法 frem 計算float類型除法的余數 drem 計算double類型除法的余數 fneg 將一個float類型的數值取反 dneg 將一個double類型的數值取反 對象和數組 對象操作指令 new 創建一個新對象 checkcast 確定對象為所給定的類型 getfield 從對象中獲取字段 putfield 設置對象中字段的值 getstatic 從類中獲取靜態字段 putstatic 設置類中靜態字段的值 instanceof 判斷對象是否為給定的類型 數組操作指令 newarray 分配數據成員類型為基本上數據類型的新數組 anewarray 分配數據成員類型為引用類型的新數組 arraylength 獲取數組長度 multianewarray 分配新的多維數組 控制流 條件分支指令 ifeq 如果等於0,則跳轉 ifne 如果不等於0,則跳轉 iflt 如果小於0,則跳轉 ifge 如果大於等於0,則跳轉 ifgt 如果大於0,則跳轉 ifle 如果小於等於0,則跳轉 if_icmpcq 如果兩個int值相等,則跳轉 if_icmpne 如果兩個int類型值不相等,則跳轉 if_icmplt 如果一個int類型值小於另外一個int類型值,則跳轉 if_icmpge 如果一個int類型值大於或者等於另外一個int類型值,則跳轉 if_icmpgt 如果一個int類型值大於另外一個int類型值,則跳轉 if_icmple 如果一個int類型值小於或者等於另外一個int類型值,則跳轉 ifnull 如果等於null,則跳轉 ifnonnull 如果不等於null,則跳轉 if_acmpeq 如果兩個對象引用相等,則跳轉 if_acmpnc 如果兩個對象引用不相等,則跳轉 比較指令 lcmp 比較long類型值 fcmpl 比較float類型值(當遇到NaN時,返回-1) fcmpg 比較float類型值(當遇到NaN時,返回1) dcmpl 比較double類型值(當遇到NaN時,返回-1) dcmpg 比較double類型值(當遇到NaN時,返回1) 無條件轉移指令 goto 無條件跳轉 goto_w 無條件跳轉(寬索引) 表跳轉指令 tableswitch 通過索引訪問跳轉表,並跳轉 lookupswitch 通過鍵值匹配訪問跳轉表,並執行跳轉操作 異常 athrow 拋出異常或錯誤 finally子句 jsr 跳轉到子例程 jsr_w 跳轉到子例程(寬索引) rct 從子例程返回 方法調用與返回 方法調用指令 invokcvirtual 運行時按照對象的類來調用實例方法 invokespecial 根據編譯時類型來調用實例方法 invokestatic 調用類(靜態)方法 invokcinterface 調用接口方法 方法返回指令 ireturn 從方法中返回int類型的數據 lreturn 從方法中返回long類型的數據 freturn 從方法中返回float類型的數據 dreturn 從方法中返回double類型的數據 areturn 從方法中返回引用類型的數據 return 從方法中返回,返回值為void 線程同步 montiorenter 進入並獲取對象監視器 monitorexit 釋放並退出對象監視器 JVM指令助記符 變量到操作數棧:iload,iload_,lload,lload_,fload,fload_,dload,dload_,aload,aload_ 操作數棧到變量:istore,istore_,lstore,lstore_,fstore,fstore_,dstore,dstor_,astore,astore_ 常數到操作數棧:bipush,sipush,ldc,ldc_w,ldc2_w,aconst_null,iconst_ml,iconst_,lconst_,fconst_,dconst_ 加:iadd,ladd,fadd,dadd 減:isub,lsub,fsub,dsub 乘:imul,lmul,fmul,dmul 除:idiv,ldiv,fdiv,ddiv 余數:irem,lrem,frem,drem 取負:ineg,lneg,fneg,dneg 移位:ishl,lshr,iushr,lshl,lshr,lushr 按位或:ior,lor 按位與:iand,land 按位異或:ixor,lxor 類型轉換:i2l,i2f,i2d,l2f,l2d,f2d(放寬數值轉換) i2b,i2c,i2s,l2i,f2i,f2l,d2i,d2l,d2f(縮窄數值轉換) 創建類實便:new 創建新數組:newarray,anewarray,multianwarray 訪問類的域和類實例域:getfield,putfield,getstatic,putstatic 把數據裝載到操作數棧:baload,caload,saload,iaload,laload,faload,daload,aaload 從操作數棧存存儲到數組:bastore,castore,sastore,iastore,lastore,fastore,dastore,aastore 獲取數組長度:arraylength 檢相類實例或數組屬性:instanceof,checkcast 操作數棧管理:pop,pop2,dup,dup2,dup_xl,dup2_xl,dup_x2,dup2_x2,swap 有條件轉移:ifeq,iflt,ifle,ifne,ifgt,ifge,ifnull,ifnonnull,if_icmpeq,if_icmpene, if_icmplt,if_icmpgt,if_icmple,if_icmpge,if_acmpeq,if_acmpne,lcmp,fcmpl fcmpg,dcmpl,dcmpg 復合條件轉移:tableswitch,lookupswitch 無條件轉移:goto,goto_w,jsr,jsr_w,ret 調度對象的實便方法:invokevirtual 調用由接口實現的方法:invokeinterface 調用需要特殊處理的實例方法:invokespecial 調用命名類中的靜態方法:invokestatic 方法返回:ireturn,lreturn,freturn,dreturn,areturn,return 異常:athrow finally關鍵字的實現使用:jsr,jsr_w,ret
程序計數器:
記錄的是馬上要執行的代碼對應的字節碼的數字
是程序執行的指針(地址),也即將來要執行的指令代碼
動態鏈接:
變量,當執行時需要找到。比如
Map<String, String> map = new HashMap<>();
Map 接口,運行時找HashMap實現,做一個鏈接(動態)
自己寫的接口,執行時去找具體實現。
本地方法棧的理解
執行引擎運行本地方法
會調用被本地方法接口,本地方法入本地方法棧,類似ava棧,也有棧針,調用C語言所實現的dll(cpp)庫,類似java的jar包
方法區(線程共享):類的所有字段和方法字節碼,以及一些特殊方法如構造函數,接口代碼也在此定義。
簡單說,所有定義的方法的信息都保存在該區域,靜態變量+常量+類信息(構造方法/接口定義)+運行時常量池都存在方法區中,
雖然Java虛擬機規范把方法區描述為堆的一個邏輯部分,但是它卻有一個別名叫做 Non-Heap(非堆),目的應該是與 Java 堆區分開來。
實例詳解java棧
棧+堆+方法區的交互關系
HotSpot是使用指針的方式來訪問對象
Java堆中會存放訪問類元數據的地址
reference存儲的就直接是對象的地址
對象類型數據是calss的末班數據