問題
首先來看看這些問題,下面會一一解答
- jvm理解,Java8虛擬機器和之前有什麼更新
- 什麼是OOM,什麼是StackOverFlowError
- JVM常用的引數調優有哪些
- 記憶體快照如何抓取,怎麼分析Fump檔案
- 談談jvm中,類載入器的認識
基本概念
首先大致瞭解一下虛擬機器內部的東西
程式計數器是一塊很小的記憶體空間,用於記錄下一條要執行的指令。每個執行緒都需要一個程式計數器,各個執行緒之中的計數器相互獨立,是執行緒中私有的記憶體空間
java虛擬機器棧
java虛擬機器棧也是執行緒私有的記憶體空間,它和java執行緒同一時間建立,儲存了區域性變數、部分結果,並參與方法的呼叫和返回
本地方法棧
本地方法棧和java虛擬機器棧的功能相似,java虛擬機器棧用於管理Java函式的呼叫,而本地方法棧用於管理本地方法的呼叫,但不是由Java實現的,而是由C實現的
java堆
為所有建立的物件和陣列分配記憶體空間,被JVM中所有的執行緒共享
方法區
也被稱為永久區,與堆空間相似,被JVM中所有的執行緒共享。方法區主要儲存的資訊是類的後設資料,方法區中最為重要的是類的型別資訊、常量池、域資訊、方法資訊,其中執行時常量池就在方法區,對永久區的GC回收,一是GC對永久區常量池的回收;二是永久區對後設資料的回收
類載入器
- 虛擬機器自帶的載入器
- 啟動類(根)載入器
- 擴充類載入器
- 應用程式載入器
雙親委託機制
- Java 虛擬機器大致結構圖
- 詳細圖
Class
類是模板,而物件是類的例項,同一個類别範本也可創造不同的例項。
Native
// native :凡是帶了native關鍵字的,說明java的作用範圍達不到了,回去呼叫底層C語言的庫!
//會進入本地方法棧
//呼叫本地方法本地介面JNI
// JNI作用:打展Java的使用,融合不同的程式語言為ava所用!最初: C、C++。
// Java 誕生的時候C、C++橫行,想要立足,必須要有調C、C++的程式
//它在記憶體區域中專門開昨了一塊標記區域: Native Method stack,登記native方法
//在最終執行的時候,載入本地方法庫中的方法透過INI
// Java程式驅動印表機
方法區
Method Area 方法區
方法區是被所有執行緒共享,所有欄位和方法位元組碼,以及一些特殊方法,如建構函式,介面程式碼也在此定義,簡單說,所有定義的方法的資訊都儲存在該區域,此區域屬於共享區間:
靜態變數、常量、類資訊(建構函式、介面定義)、執行時常量池存在方法區中,但是例項變數存在堆記憶體中,和方法區無關。
static final class 常量池
方法執行時入棧,方法的引用在棧,方法在堆裡面。
public class Test {
private int a;
private String name = "haha";
public static void main(String[] args) {
Test test1 = new Test();
test1.a = 1;
test1.name = "hudu";
}
}
對於上面的程式碼,執行過程在底層的實現過程為:
棧:資料結構
程式:資料結構+演算法
棧:先進後出、後進先出
佇列:先進先出(FIFO:First Input First Output)
為什麼main()方法先執行,最後結束
檢視下面的程式碼
public class Test2 {
public static void main(String[] args) {
new Test2().test();
}
public void test() {
a();
}
public void a() {
test();
}
}
常見的棧溢位
最後會報錯:Exception in thread “main” java.lang.StackOverflowError
由圖可知,正常的遞迴呼叫會有結束的限制,然而上面會方法之間不停呼叫,就出現了棧溢位。
棧:棧記憶體,主管程式的執行,生命週期和執行緒同步;執行緒結束,棧記憶體就釋放了,對於棧來說,不存在垃圾回收機制。
一旦執行緒結束,棧就 Over 了
棧:8大基本型別,物件的引用,例項的方法
棧執行原理:棧幀
程式正在執行的方法一定在棧的頂部
棧+堆+方法區:互動關係
java8中,執行時常量池在方法區中,字串常量池,靜態變數在堆中,原空間方法實現。
三種 JVM
- Sun 公司 HotSpot
- BEA
- IBM
堆
Heap,一個JVM 只有一個堆記憶體,堆記憶體是可以調整大小的
類載入器讀取了類檔案後,一般會把什麼放到堆中?類,方法,常量,變數。儲存我們所有引用型別的真實物件
類方法(靜態方法)儲存在方法去裡
堆記憶體彙總還要分為三個區域:
- 新生區
- 老年區
- 永久區
GC 垃圾回收主要在新生區和老年區
假設記憶體滿了,OOM,堆記憶體不夠!java. lang .OutOfMemoryError: Java hejap space
在JDK8之後,永久儲存區改了個名字(元空間)
新生區
- 類:誕生和成長的地方,甚至死亡,
- 伊甸園,所有的物件都在伊甸園區new出來的
- 倖存者區(0,1)
老年區
經過研究,99%的物件都是臨時物件
永久區
這個區域常駐記憶體,用來存放一些,jdk自身攜帶的Class物件,Interface後設資料,儲存的是java執行時的一些環境或類資訊,這個區域不存在垃圾回收機制,關閉jvm虛擬機器就會釋放這個區域的記憶體。
一個啟動類,載入了太多的第三方jar包,Tomcat部署了太多的應用。大量動態生成的反射類,不斷被載入,知道記憶體慢,出現OOM
- jdk1.6之前:永久代,常量池在方法區中
- jdk1.7:永久代,但是慢慢的退化,去
永久代
,常量池在堆中 - jdk1.8之後:無永久代,常量池在元空間
元空間,邏輯上存在,物理上不存在
下面透過程式碼驗證
public class Test4 {
public static void main(String[] args) {
//返回jvm的初始化總記憶體
long total = Runtime.getRuntime().totalMemory();
//返回jvm虛擬機器的使用的最大記憶體
long max = Runtime.getRuntime().maxMemory();
System.out.println("max="+max+"位元組\t"+(max/(double)1024/1024)+"MB");
System.out.println("total="+total+"位元組\t"+(total/(double)1024/1024)+"MB");
//預設情況下:分配總記憶體是電腦的1/4,而初始化是1/64
//305664K+699392K = 1,005,056k = 981.5MB
}
}
輸出結果:
max=1029177344位元組 981.5MB
total=1029177344位元組 981.5MB
Heap
PSYoungGen total 305664K, used 15729K [0x00000007aab00000, 0x00000007c0000000, 0x00000007c0000000)
eden space 262144K, 6% used [0x00000007aab00000,0x00000007aba5c420,0x00000007bab00000)
from space 43520K, 0% used [0x00000007bd580000,0x00000007bd580000,0x00000007c0000000)
to space 43520K, 0% used [0x00000007bab00000,0x00000007bab00000,0x00000007bd580000)
ParOldGen total 699392K, used 0K [0x0000000780000000, 0x00000007aab00000, 0x00000007aab00000)
object space 699392K, 0% used [0x0000000780000000,0x0000000780000000,0x00000007aab00000)
Metaspace used 3093K, capacity 4496K, committed 4864K, reserved 1056768K
class space used 335K, capacity 388K, committed 512K, reserved 1048576K
可以看到PSYoungGen+ParOldGen就等於總記憶體大小了
實際上方法區物理上不在堆記憶體中。
-Xms1024m -Xmx1024m -XX:+PrintGCDetails
出現OOM:
- 嘗試擴大堆記憶體檢視結果
- 分析記憶體,看一下哪個地方出現問題
在一個專案中,突然出現OOM,如何排除
- 能夠看到程式碼第幾行出錯:記憶體快照工具,MAT,Jprofile
- Debug,一行一行分析程式碼!
MAT,Jprofile
- 分析Dump記憶體檔案,快速定位記憶體洩漏
- 獲得堆中資料
- 獲得大的物件
- 。。。
//-Xms設定初始化記憶體分配大小 1/64
//-Xmx設定最大分配記憶體大小,預設1/4
//-XX:+PrintGCDetails //列印垃圾回收資訊
//-XX:+HeapDumpOnOutOfMemoryError //OOM Dump
例如:
-Xms1m -Xmx8m -XX:HeapDumpOnOutOfMemoryError
本作品採用《CC 協議》,轉載必須註明作者和本文連結