內存結構

內存結構

程序計數器(寄存器)

作用:記住下一條 jvm 指令的執行地址

特點:

  • 是線程私有的

    為了線程切換後能恢復到原來的執行位置,每條線程都需要有一個獨立的程序計數器,各個計數器之間互不影響。

  • 不會存在內存溢出

虛擬機棧

定義

Java Virtual Machine Stacks (Java 虛擬機棧)

  • 每一個線程都會開闢一個虛擬機棧,用於存放棧幀;棧幀用於存儲局部變量表、操作數棧、動態連接和方法出口等信息。

    局部變量表存放了編譯期可見的各種基本數據類型,這些數據類型在表中的存儲空間以局部變量槽(slot)表示,

  • 每個線程只能有一個活動棧幀,對應着當前正在執行的那個方法。

  • 如果線程請求的棧深度大於虛擬機所允許的深度,拋出SO異常;如果棧擴展無法申請到足夠的內存拋出OOM異常。

問題 ?

  1. 垃圾回收是否涉及棧內存?

    不是,棧內存隨着方法執行的結束而釋放,並不會被垃圾回收釋放,垃圾回收釋放的堆內存。

  2. 棧內存分配越大越好嗎?

    不是,棧內存分配越大,會導致線程數量減少。

  3. 方法內的局部變量是否線程安全?

  • 如果方法內局部變量沒有逃離方法的作用範圍,它是線程安全的
  • 如果是局部變量引用了對象,或逃離方法的作用範圍,需要考慮線程安全

棧內存溢出

  • 棧幀過多導致棧內存溢出
  • 棧幀過大導致棧內存溢出

線程運行診斷

1、cpu 佔用過多

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

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

  • jstack 進程id

    可以根據線程id 找到有問題的線程,進一步定位到問題代碼的源碼行號

2、程序運行很長時間沒有結果

本地方法棧

調用本地方法和操作系統交互,例如Object 里的方法,方法前有 native 修飾。

定義

通過 new 關鍵字,創建對象都會使用堆內存

特點

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

堆內存溢出

垃圾回收會對無用的對象進行回收,但如果一直有對象被創建,並且對象一直被使用,最終會導致堆內存溢出。

堆內存診斷

1、 jps 工具

查看當前系統中有哪些 java 進程

2、map 工具

查看堆內存佔用情況

 jhsdb jmap --heap --pid 進程id

3、jconsole 工具

圖形界面的,多功能的監測工具,可以連續監測

案例

  • 垃圾回收後,內存佔用仍然很高

    打開jdk按照目錄:jvisualvm.exe

方法區

方法區內存溢出

  • 1.8前會導致永久代溢出
  • 1.8後會導致元空間溢出

運行時常量池

  • 常量池就是一張表,虛擬機指令根據這張表找到要執行的類名、方法名、參數類型、字面量等信息
  • 運行時常量池,當該類被加載時,它的常量池信息會放入運行時常量池,並把裏面的符號地址變為真實地址

StringTable

  • 常量池中的字符串僅僅是符號,只有第一次用到時才變為對象
  • 利用串池的機制,避免重複創建字符串對象
  • 字符串變量拼接的原理是StringBuilder
  • 字符串常量拼接的原理是編譯器優化
  • 可以使用intern 方法,主動將串池中還沒有的字符串對象加入串池
    • 1.8 將這個字符串對象嘗試放入串池,如果有則不放入,沒有則放入,返回串池中的對象
    • 1.6 將這個字符串對象嘗試放入串池,如果有則不放入,沒有則複製一份此對象,放入串池,返回串池中的對象

StringTable 調優:

  • -Xms500m -Xmx500m -XX:PrintStringTableStatistics -XX:StringTableSize =

    -jvm啟動時分配的最大內存 -jvm運行過程中分配的最大內存 -打印串池中的統計信息 -設置串池中桶的個數

  • 有大量的重複的字符串,可以讓字符串入池,減少字符串的個數,減少堆內存的使用。

直接內存

  • 常見於NIO操作,用於數據緩衝區
  • 分配回收成本高,但讀寫性能高
  • 不受jvm內存回收管理

直接內存釋放原理

  • 使用了Unsafe 對象完成直接內存的分配回收,並且回收需要主動調用freeMemory方法
  • ByteBuffer 的實現類內部,使用了 Cleaner(虛引用) 來監測 ByteBuffer 對象,一旦 ByteBuffer 對象被垃圾回收,那麼就會由ReferenceHandler 線程通過 Cleaner 的 clean 方法調用 freeMemory 來釋放直接內存

-XX:+DisableExplictGC 關閉顯示的gc:System.gc()