Java代碼編譯是由Java源碼編譯器來完成,也就是Java代碼到JVM字節碼(.class文件)的過程。 Java字節碼的執行是由JVM執行引擎來完成
Java代碼編譯和執行的整個過程包含了以下三個重要的機制
1、Java源碼編譯機制
①分析和輸入到符號表
②注解處理
③語義分析和生成class文件
最后生成的class文件由以下部分組成:
①結構信息:包括class文件格式版本號及各部分的數量與大小的信息
②元數據:對應于Java源碼中聲明與常量的信息。包含類/繼承的超類/實現的接口的聲明信息、域與方法聲明信息和常量池
③方法信息:對應Java源碼中語句和表達式對應的信息。包含字節碼、異常處理器表、求值棧與局部變量區大小、求值棧的類型記錄、調試符號信息
2、類加載機制
JVM的類加載是通過ClassLoader及其子類來完成的
3、類執行機制
JVM執行class字節碼,線程創建后,都會產生程序計數器(PC)和棧(Stack),程序計數器存放下一條要執行的指令在方法內的偏移量,棧中存放一個個棧幀,每個棧幀對應著每個方法的每次調用,而棧幀又是有局部變量區和操作數棧兩部分組成,局部變量區用于存放方法中的局部變量和參數,操作數棧中用于存放方法執行過程中產生的中間結果。
所有線程共享的內存空間 堆空間:JVM規范中規定,所有對象實例以及數組都要在堆上進行分配。一般來說,堆空間都有一個默認大小,取決于JVM實現,而且可以根據需要動態擴展。當創建對象需要在堆上分配空間,而且堆本身的空間不夠也無法申請額外的內存空間,則會拋出OutOfMemoryError異常。 方法區:存儲已被JVM加載的類信息、方法信息、常量和靜態變量等數據。方法區(Method Area)與Java堆一樣,是各個線程共享的內存區域,它用于存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯后的代碼等數據。靜態域和常量池(Runtime Constant Pool)就是方法區的一部分。
每個線程獨有的內存空間 PC程序計數器:一塊較小的內存空間,每個線程都一個程序計數器,用來表示線程當前需要執行的Java指令地址。 虛擬機??臻g:JVM在執行一個線程的方法時,會為這個線程方法創建一個棧幀(可以理解為JVM??臻g中的一段存儲區域)。這個棧幀用于存儲局部變量表、操作數棧、動態鏈接和方法入口信息。 本地方法棧空間:跟虛擬機??臻g類似,只是用來存儲本地方法調用的相關信息。
堆內存=Young(新生代,占1/3)+Old(年老代,占2/3)。 新生代=Eden+Survivor(from)+Survivor(to)。比例為:8:1:1。 1、new的對象都是在Eden區。 2、過段時間執行GC后存活下來的會被放到Survivor(from)區。 3、再過段時間GC執行的時候如果Survivor(from)區滿了就講Survivor(from)存活下來的復制到Survivor(to),一直輪換復制,這就是為什么需要兩個Survivor區。 4、繼續執行GC,Survivor存活下來的會放到Old區。
1:停止-復制(stop and copy)。效率低,需要的空間大,優點,不會產生碎片。Young使用的就是這種算法。
2:標記 - 清除算法 (mark and sweep)。主要是首先標記出所有需要回收的對象,然后回收所有需要回收的對象。速度較快,占用空間少,標記清除后會產生大量的碎片。Old使用的是這種算法。
-Xms | 初始堆大小。如:-Xms256m |
---|---|
-Xmx | 最大堆大小。如:-Xmx512m |
-Xmn | 新生代大小。通常為 Xmx 的 1/3 或 1/4。新生代 = Eden + 2 個 Survivor 空間。實際可用空間為 = Eden + 1 個 Survivor,即 90% |
-Xss | JDK1.5+ 每個線程堆棧大小為 1M,一般來說如果棧不是很深的話, 1M 是絕對夠用了的。 |
-XX:NewRatio | 新生代與老年代的比例,如 –XX:NewRatio=2,則新生代占整個堆空間的1/3,老年代占2/3 |
-XX:SurvivorRatio | 新生代中 Eden 與 Survivor 的比值。默認值為 8。即 Eden 占新生代空間的 8/10,另外兩個 Survivor 各占 1/10 |
-XX:PermSize | 永久代(方法區)的初始大小 |
-XX:MaxPermSize | 永久代(方法區)的最大值 |
-XX:+PRintGCDetails | 打印 GC 信息 |
-XX:+HeapDumpOnOutOfMemoryError | 讓虛擬機在發生內存溢出時 Dump 出當前的內存堆轉儲快照,以便分析用 |
新聞熱點
疑難解答