- 適用於 JDK 23 的 GraalVM (最新)
- 適用於 JDK 24 的 GraalVM (搶先體驗)
- 適用於 JDK 21 的 GraalVM
- 適用於 JDK 17 的 GraalVM
- 封存
- 開發版本
原生記憶體追蹤 (NMT) 與 Native Image
原生記憶體追蹤 (NMT) 是一種服務性功能,用於記錄應用程式的堆外記憶體使用情況。術語「堆外記憶體」有時與「原生記憶體」或「非受管理記憶體」互換使用。這基本上是指任何不由垃圾收集器管理的記憶體。
與 HotSpot JVM 不同,Native Image 主要使用由其垃圾收集器管理的已收集堆上的記憶體。然而,Native Image 仍然在許多地方使用原生記憶體,以避免在受管理堆上分配記憶體。一些範例包括 JFR、垃圾收集器和堆傾印。也可以使用 Unsafe#allocateMemory(long)
在應用程式層級直接請求原生記憶體。
啟用原生記憶體追蹤 #
NMT 支援預設為停用,必須在建置時明確啟用。
若要使用 NMT 建置原生可執行檔,請使用 --enable-monitoring=nmt
選項。如果在建置時包含 NMT,則它會在執行時始終啟用。這與 HotSpot 不同,HotSpot 允許在執行時啟用/停用 NMT。
native-image --enable-monitoring=nmt YourApplication
當從原生可執行檔啟動應用程式時,新增 -XX:+PrintNMTStatistics
會指示 NMT 在應用程式完成時將報告寫入標準輸出。
./yourapplication -XX:+PrintNMTStatistics
效能 #
在 Native Image 上,NMT 的 CPU 和記憶體消耗都相當小。與其他服務性功能 (例如 JFR) 相比,NMT 的額外負荷相對非常小。
NMT 的 JFR 事件 #
Native Image 中支援 OpenJDK JFR 事件 jdk.NativeMemoryUsage
和 jdk.NativeMemoryUsageTotal
。
您也可以存取兩個 Native Image 特定 JFR 事件:jdk.NativeMemoryUsagePeak
和 jdk.NativeMemoryUsageTotalPeak
。建立這些 Native Image 特定事件是為了公開透過從 OpenJDK 移植過來的 JFR 事件未公開的峰值使用資料。這些新事件標示為實驗性。您可能需要在軟體 (例如 JDK Mission Control) 中啟用實驗性事件才能檢視它們。
若要將這些 JFR 事件用於 NMT,請在叫用 native-image
工具時傳遞 --enable-monitoring=jfr,nmt
選項來啟用 JFR 監控,然後在執行時開始 JFR 錄製。(在使用 Native Image 的 JDK Flight Recorder (JFR)中了解更多資訊)。
請參閱下方範例,了解使用 jfr
命令列工具檢視時,新事件的外觀
jfr print --events jdk.NativeMemoryUsagePeak recording.jfr
jdk.NativeMemoryUsagePeak {
startTime = 13:18:50.605 (2024-04-30)
type = "Threading"
peakReserved = 424 bytes
peakCommitted = 424 bytes
countAtPeak = 4
eventThread = "JFR Shutdown Hook" (javaThreadId = 63)
}
jdk.NativeMemoryUsagePeak {
startTime = 13:18:50.605 (2024-04-30)
type = "Unsafe"
peakReserved = 14.0 kB
peakCommitted = 14.0 kB
countAtPeak = 2
eventThread = "JFR Shutdown Hook" (javaThreadId = 63)
}
限制 #
在 HotSpot 上,NMT 有兩種模式:摘要和詳細。在 Native Image 中,目前僅支援 NMT 摘要模式。無法使用啟用呼叫站追蹤的詳細模式。也尚無法擷取基準。如果您對支援這些其他功能感興趣,請向 GitHub 上的 GraalVM 專案提交請求。
目前僅提供 Malloc 追蹤功能 (截至適用於 JDK 23 的 GraalVM)。
Native Image 與 HotSpot 相同,只能追蹤在 VM 層級和使用 Unsafe#allocateMemory(long)
進行的分配。例如,如果程式庫程式碼或應用程式程式碼直接呼叫 malloc,該呼叫會略過 NMT 會計,且不會被追蹤。