JVM相關 :1.內(nèi)存結構

Java虛擬機在執(zhí)行java程序的過程中會把它所管理的內(nèi)存化分為若干個不同的數(shù)據(jù)區(qū)域。這些區(qū)域有各自的用途,以及創(chuàng)建和銷毀的時間。有些區(qū)域隨之虛擬機進程的啟動而一直存在,有些區(qū)域則依賴用戶線程的啟動和結束而建立和銷毀。

jvm-內(nèi)存結構.png

1. 程序計數(shù)器 Program Counter Register

1.1 定義

<font color="green">作用:記住下一條jvm指令的執(zhí)行地址。</font>

<font color="green">特點:</font>

  • 線程私有
  • 不會存在內(nèi)存溢出

<font color="green">為了線程切換后能恢復到正確的執(zhí)行位置,每條線程都要有一個獨立的程序計數(shù)器,各線程之間的計數(shù)器互不影響,獨立存儲。所以這部分是線程私有的。 </font>

2. 虛擬機棧 Java Virtual Machine Stacks

2.1 定義

  • 每個線程運行時所需要的內(nèi)存稱為虛擬機棧
  • 每個棧由多個棧幀組成,棧幀:每個方法執(zhí)行所占用的內(nèi)存
    • 棧幀用于存儲局部變量表、操作數(shù)棧、動態(tài)鏈接、方法出口等信息
    • 一個方法從調(diào)用到執(zhí)行完畢的過程,都對應著一個棧幀在虛擬機棧中從入棧到出棧的過程
  • 每個線程只能有一個活動棧幀,對應著當前正在執(zhí)行的那個方法

<font color="green">局部變量表</font>

存放方法參數(shù)和方法內(nèi)部定義的局部變量。

存放編譯期可知的各種基本數(shù)據(jù)類型、引用數(shù)據(jù)類型、return Address類型

局部變量表的內(nèi)存空間在編譯期完成分配,當進入一個方法時,這個方法需要在幀分配多少內(nèi)存是固定的。

在方法運行期間是不會改變局部變量表的大小的。

<font color="orage">問題辨析:</font>

1.垃圾回收是否涉及棧內(nèi)存?

2.棧內(nèi)存分配越大越好嗎?

3.方法內(nèi)的局部變量是否線程安全?

  • 如果方法內(nèi)局部變量沒有逃離方法作用域,它是線程安全的

2.2 棧內(nèi)存溢出

  • 棧幀過多導致內(nèi)存溢出
  • 棧幀過大導致內(nèi)存溢出

2.3 線程運行診斷

案例1:cpu占用過多

  • 用top定位哪個進程對cpu的占用過高

  • ps H -eo pid,tid,%cpu | grep 進程id (用ps進一步定位是哪個線程引起的)

  • jstack 進程id

    • 找到有問題的線程,定位問題代碼的源碼位置

3. 本地方法棧

本地方法棧為虛擬機使用到的native方法服務。

4. 堆 Heap

4.1 定義

  • 通過new 關鍵字,創(chuàng)建對象都會使用堆內(nèi)存

<font color="green"> 特點:</font>

  • 它是線程共享的,堆中的對象都需要考慮線程安全問題
  • 有垃圾回收機制

4.2 堆內(nèi)存溢出

4.3 堆內(nèi)存診斷

  • jps工具

    查看當前系統(tǒng)有哪些java進程

  • jmap

    查看堆內(nèi)存占用情況 jmap -head 進程id

  • jconsole

    一個可視化工具

5. 方法區(qū) Method Area

5.1 定義

5.2 組成

方法區(qū).png

5.3 方法區(qū)內(nèi)存溢出

  • 1.8 以前會導致永久代內(nèi)存溢出
java.lang.OutOfMemeryError: PermGen space
-XX:MaxPermSize=8m
  • 1.8 以后會導致元空間內(nèi)存溢出
java.lang.OutOfMemeryError: Metaspace
-XX:MaxMetaspaceSize=8m

5.4 運行時常量池

  • 常量池就是一張表,虛擬機指令根據(jù)這張常量表找到要執(zhí)行的類名、方法名、參數(shù)類型、字面量等信息

  • 運行時常量池,常量池是 *.class 文件中的。當該類被加載,它的常量池信息就會放入運行時常量池中。

    并把里面的符號地址變?yōu)檎鎸嵉牡刂?/p>

5.5 StringTable

先來看一段代碼

String s1 = "a";
String s2 = "b";
String s3 = "a" + "b";
String s4 = s1 + s2;
String s5 = "ab";
String s6 = s4.intern();

System.out.println(s3 == s4);
System.out.println(s3 == s5);
System.out.println(s3 == s6);

String x2 = new String("c") + new String("d");
String x1 = "cd";
x2.intern();

//如果調(diào)換了最后兩行代碼的位置呢?如果是jdk 1.6呢?
System.out.println(x2 == x1);

5.6 StringTable特性

  • 常量池中的字符串僅是符號,第一次使用時才變成對象
  • 利用串池的機制,來避免重復創(chuàng)建字符串對象
  • 字符串變量的拼接原理是 StringBuilder(1.8)
  • 字符串常量拼接的原理是編譯器優(yōu)化
  • 可以使用intern()方法,主動將串池中還沒有的字符串對象放入串池
    • 1.8 將這個字符串對象嘗試放入串池,如果有則并不會放入,如果沒有則會放入串池,會把串池中的對象返回。
    • 1.6 將這個字符串對象嘗試放入串池,如果有則并不會放入,如果沒有會把此對象復制一份,放入串池,會把串池中的對象返回
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容