一:介紹
- 什麼是JVM
定義:java virtual meachine -java運行時環境(java二進制字節碼的運行環境)。 - 好處:
一次編寫到處運行
自動內存管理,垃圾回收
數組下標越界檢查
多態
java虛擬機:
java的內存結構包括:
- 程序計數器
- 虛擬機棧
- 本地方法棧
- 堆
- 方法區
1.1 程序計數器
- java代碼在執行的過程:首先被編譯成二進制字節碼(jvm指令),然後通過解釋器生成爲機器碼,最後纔會被CPU執行。
- 而解釋器在執行每一條字節碼指令時,需要程序計數器來指定需要執行的指令。此時程序計數器中存儲的是jvm下一個執行的地址
- 正是因爲能編輯爲機器碼,jvm纔有一次編輯,多平臺使用。因爲無論linux和windows系統,都會執行機器碼
特點:
- 線程私有
- 不會出現內存泄漏
1.2 棧
1.2.1棧的定義
定義:
- 每個線程運行時所需要的內存,稱爲虛擬機棧
- 每個棧由多個棧幀組成,對應着每次方法調用時所佔用的內存
- 每個線程只能有一個活動棧幀(正在執行的方法),對應着當前正在執行的那個方法
- 特點:先進後出
一個線程需要一個棧;一個棧幀對應一個方法的調用;
棧和棧幀的關係:線程執行方法的時候,會調用方法,會將棧棧放入棧內,當方法執行完後,會將棧幀釋放掉
問題解析:
1:垃圾回收是否涉及棧內存
不涉及,方法執行完後,對應的棧幀就會被出棧,被釋放掉,不涉及垃圾回收
2:棧內存分配越大越好嗎?
不是:物理內存大小是一定的,當棧內存大時,線程數就會少。
3:方法內的局部變量是否線程安全?
- 如果方法內局部變量沒有逃離方法的作用訪問,是線程安全的
- 如果是局部變量引用了對象,並逃離方法的作用方法,需要考慮線程安全
查看線程是否安全:看這個變量對多個線程是共享的,還是私有的
public class Demo{
static void hello(){
int x=0;
for (int i=0;i<100;i++){
x++;
}
System.out.println(x);
}
}
此時線程安全
此時局部變量是線程不安全的
public class Demo{
static void hello(){
static int x=0;
for (int i=0;i<100;i++){
x++;
}
System.out.println(x);
}
}
1.2.2 棧內存溢出
STACKOVERFLOWERROE
什麼情況會導致內存溢出
- 棧幀多時,一直有棧幀進棧;當遞歸次數多時
- 棧幀過大導致內存溢出,
1.2.3 線程運行診斷
-
案例一:cpu佔用過多
定位- 用top定位哪個線程對cpu佔用過高
- ps -H pid,tid,%cpu | grep 進程id,(用ps命令進一步定位那個線程引起的cpu佔用過高)
- jstack 進程id
- 可以根據線程id,找到問題的線程,進一步定位到出現問題的代碼
-
案例二:一段程序,運行好長時間,沒有等到返回的結果