什么是Java對象分配率?

jopen 9年前發布 | 8K 次閱讀 Java Java開發

類似“不可持續的內存分配率”和“你需要維持低的內存分配率”這樣的短語看起都像是屬于 Java 冠軍(Java Champions)的專有詞匯。復雜、嚇人、充滿神秘色彩。

這些詞語經常出現,但是如果你深入了解這些概念,它的神秘色彩就煙消云散了。這篇文章將試著揭開上面這些術語的神秘面紗。

什么是內存分配率?我們為什么要關心它?

內存分配率是指單位時間內分配內存的總數量,通常用 MB/sec 表示。不過,如果你樂意,也可以用 PB/year 來表示。這就是全部的內容——沒那么神秘,僅僅是指 Java 代碼在一定時期內內存分配的大小。

不過只知道這一點沒有太大的意義。如果你能忍受,我將帶你在實踐中應用這個概念。高分配率意味著你的程序存在性能問題。從實踐角度來說,主要影響是使得 GC(Garbage Collection) 成為了瓶頸。從硬件角度來說,即使常用的硬件也能支持每核幾 GB/sec 的分配率。而實際上,你的分配率不會超過 1 GB/sec/core。所以你可以放心,硬件基本不可能成為應用的瓶頸。

所以,當我們關注 GC 的時候,就可以和真實情況類比了——如果你創建很多的成員,之后就需要做很多清理工作。我們知道,JVM 建立垃圾回收機制需要知道內存分配率,由此來改變 GC 執行的頻率和 GC 停頓的時間。

內存分配率的測量

我們開始測量內存分配率。我們設置 JVM 參數:-XX:+PrintGCDetails -XX:+PrintGCTimeStamps 來打開 GC 日志。現在,JVM 開始以下列方式記錄 GC 停頓日志:

0.291: [GC (Allocation Failure) [PSYoungGen: 33280K->5088K(38400K)] 33280K->24360K(125952K), 0.0365286 secs] [Times: user=0.11 sys=0.02, real=0.04 secs] 
0.446: [GC (Allocation Failure) [PSYoungGen: 38368K->5120K(71680K)] 57640K->46240K(159232K), 0.0456796 secs] [Times: user=0.15 sys=0.02, real=0.04 secs] 
0.829: [GC (Allocation Failure) [PSYoungGen: 71680K->5120K(71680K)] 112800K->81912K(

根據上述 GC 日志,我們可以從年青代(Young Generation)上一次回收后的大小及下一次回收前的大小來計算出分配率。利用上面的例子,我們可以抽取出如下信息:

  • JVM 啟動291毫秒后,加載的對象大小是33280K。第一次 minor GC 清理后,年青代剩余的對象大小是 5088K。
  • 啟動446毫秒后,年青代占用的空間已經增長到38368K,并觸發了下一次 GC,這次 GC 后,年青代占用的空間減少到5120K。
  • 啟動829毫秒后,年青代的大小是71680K,GC 后再次減少到 5120K。
  • </ul>

    這些數據用如下的表格展示,計算出來的內存分配率添加年青代占用空間的后面:

    </tr> </tbody>

    </tr>

    </tr>

    </tr>

    </tr> </tbody> </table>

    有了這些信息,我們就可以說對這個特定軟件,在測量期間的內存分配率是161 MB/sec。

    影響分析

    現在,通過這些信息,我們能夠明白改變內存分配率,可以增加或減少 GC 停頓的頻率,從而影響應用的吞吐率。首先,也是最重要的,你應該注意只有 Minor GC 清理年青代的停頓才會受影響。老年代(Old Generation)的清理,無論是頻率還是持續時間都不直接受分配率的影響,但是受增長率(promotion rate)的影響,增長率是下一篇文章討論的術語。

    了解這些后,我們就只需要關注 Minor GC 的停頓,我們應該更進一步的去理解在年青代內部內存池的不同之處。因為內存分配是在 Eden 區中進行的,我們可以直接看 Eden 區的大小對分配率的影響。所以我們可以假設,隨著 Eden 區的增長,minor GC 停頓頻率頻率會降低,應用就能滿足更快的分配率。

    事實上,當我們采用不同的 Eden 區大小(-XX:NewSize -XX:MaxNewSize 和 -XX:SurvivorRatio參數)來執行相同的實例時,我們可以看到兩種不同的內存分配率:

    事件 時間 添加年輕代之前 添加年輕代之后 已分配 分配率
    1st GC 291ms 33,280KB 5,088KB 33,280KB 114MB/sec
    2nd GC 446ms 38,368KB 5,120KB 33,280KB 215MB/sec
    3rd GC 829ms 71,680KB 5,120KB 66,560KB 174MB/sec
    Total 829ms N/A N/A 133,120KB 161MB/sec
sesese色