線上 Java 8 進程 top 顯示 VIRT 達 50GB+,但 RES 僅 2GB,物理內存無壓力,卻觸發監控告警(部分監控系統以 VIRT 判斷資源使用)。
VIRT 高 ≠ 內存洩漏。源於 glibc malloc Arena 機制 在 64 位系統預分配巨大虛擬地址空間(每 Arena 64MB,默認 128 個 = 8GB),配合 MAP_NORESERVE 不佔用物理頁。Java 8 Metaspace 使用本地內存,線程增多導致 Arena 激增,VIRT 虛高。
void *mem = mmap(0, 4UL * 1024 * 1024 * 1024 * 1024, // 4TB
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
MAP_NORESERVE 告訴內核:不預分配物理頁/交換空間,僅預留虛擬地址範圍。進程實際只在首次寫入頁時觸發缺頁中斷分配物理內存。
HEAP_MAX_SIZE = 64MB (64位) 虛擬空間:mmap(..., MAP_NORESERVE)。MALLOC_ARENA_MAX = 128 (CPU 核數 × 8)。ClassLoader 持有。# 查看進程內存映射,大量 64MB 區域標記 [anon]
pmap -x | grep -E '65404|65536' | head -20
# 統計 Arena 數量
grep -c 'rw.*\[anon\]' /proc//maps
export MALLOC_ARENA_MAX=4 # 在啟動腳本/服務配置中設置
# Hadoop/YARN 推薦 4,防止 VIRT 觸發容器殺進程
malloc_conf 微調,JDK 11+ Metaspace 內存管理優化。memory.limit_in_bytes 基於 RSS。VIRT 虛高是 虛擬地址空間預留 而非實際內存佔用。通過 MALLOC_ARENA_MAX 限制 Arena 數量可大幅降低 VIRT,消除誤報。核心認知:**關注物理內存 (RSS) 與 GC 行為,而非虛擬地址大小。**