JAVA運行時數據區
線程共享:方法區 堆內存 (老年代、新生代(S0、S1)) 隨gc而創建和銷毀
線程獨占部分 虛擬機棧 本地方法棧 程序計數器 隨線程生命周期而創建和銷毀
方法區: 運行時常量池 字符串常量 (non-heap)
- 方法區是各個線程共享的內存區域
- JVM用來存儲加載的類信息、常量、靜態變量、編譯后的代碼等數據
- 虛擬機規范中這是一個邏輯區劃。具體實現根據不同虛擬機來實現。
- 如:oracle的HotSpot在java7中方法區放在永久代,java8放在元數據空間,并且通過GC機制對這個區域進行管理
堆內存:
- 還可以細分為:老年代、新生代(Eden、From Survivor、To Survivor)
- JVM啟動時創建。
- 存放對象的實例。
- 垃圾回收器主要就是管理堆內存。
- 如果滿了,就會出現OutOfMemoryError。
虛擬機棧
- 每個線程都在這個空間有一個私有的空間。
- 線程棧由多個棧幀組成。
- 一個線程會執行一個或多個方法,一個方法對應一個棧幀
- 棧幀內容包含:局部變量表、操作數棧、動態鏈接、方法返回地址、附加信息等。
- 棧內存默認最大是1M,超出則拋出StackOverflowError
本地方法棧
- 本地方法棧與虛擬機棧的功能類似, 虛擬機棧是為虛擬機執行Java方法而準備的, 本地方法棧是為虛擬機使用Native本地方法而準備的
- Hotspot虛擬機中虛擬機棧與本地方法棧的實現方式一樣, 超出大小后也會拋StackOverFlowError
程序計數器
- 記錄當前線程執行字節碼的位置,存儲的是字節碼指令地址,如果執行的Native方法,則計數器值為空。
- 每個線程都在一個空間有一個私有的空間,占用內存空間很少。
- CPU同一時間,只會執行一條線程中的指令。JVM多線程會輪流切換并分配CPU執行時間的方式。
- 為了線程切換后,需要通過程序計數器,來恢復正確的執行位置。
javap -v Demo1.class > Demo1.txt 解析 查看指令命令
實際操作例子
public class Demo1{ public static void main(String[] args){ int x = 500; int y = 100; int a = x / y; int b = 50; System.out.println(a + b); } }
經過代碼解析文件
Classfile /D:/work/NetEase/課程/vip/高性能編程/多線程并發編程/1.JAVA基礎/資料包/part-1/Demo1.class Last modified 2018-11-16; size 414 bytes MD5 checksum ae6fa820973681b35609c75631cb255b Compiled from "Demo1.java" public class Demo1 minor version: 0 // 版本號 major version: 52 // 版本號 flags: ACC_PUBLIC, ACC_SUPER // 訪問控制 Constant pool: // 類信息解析出來的靜態常量池 #1 = Methodref #5.#14 // java/lang/Object."<init>":()V #2 = Fieldref #15.#16 // java/lang/System.out:Ljava/io/PrintStream; #3 = Methodref #17.#18 // java/io/PrintStream.println:(I)V #4 = Class #19 // Demo1 #5 = Class #20 // java/lang/Object #6 = Utf8 <init> #7 = Utf8 ()V #8 = Utf8 Code #9 = Utf8 LineNumberTable #10 = Utf8 main #11 = Utf8 ([Ljava/lang/String;)V #12 = Utf8 SourceFile #13 = Utf8 Demo1.java #14 = NameAndType #6:#7 // "<init>":()V #15 = Class #21 // java/lang/System #16 = NameAndType #22:#23 // out:Ljava/io/PrintStream; #17 = Class #24 // java/io/PrintStream #18 = NameAndType #25:#26 // println:(I)V #19 = Utf8 Demo1 #20 = Utf8 java/lang/Object #21 = Utf8 java/lang/System #22 = Utf8 out #23 = Utf8 Ljava/io/PrintStream; #24 = Utf8 java/io/PrintStream #25 = Utf8 println #26 = Utf8 (I)V { public Demo1(); descriptor: ()V flags: 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 1: 0 public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=3, locals=5, args_size=1 // main方法對應棧幀的操作數棧深度、本地變量數量、參數數量 0: sipush 500 3: istore_1 4: bipush 100 6: istore_2 7: iload_1 8: iload_2 9: idiv 10: istore_3 11: bipush 50 13: istore 4 15: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 18: iload_3 19: iload 4 21: iadd 22: invokevirtual #3 // Method java/io/PrintStream.println:(I)V 25: return LineNumberTable: line 3: 0 line 4: 4 line 5: 7 line 6: 11 line 7: 15 line 8: 25 } SourceFile: "Demo1.java"