首頁>技術>

環節。這裡總結下我們專案裡的最佳實踐。

Java Heap 基礎知識預設情況下,JVM 自動分配的 heap 大小取決於機器配置。比如我們到一臺 64G 記憶體伺服器:

java -XX:+PrintFlagsFinal -version | grep -Ei "maxheapsize|maxram"    uintx DefaultMaxRAMFraction                     = 4                                   {product}    uintx MaxHeapSize                              := 16875782144                         {product} uint64_t MaxRAM                                    = 137438953472                        {pd product}    uintx MaxRAMFraction                            = 4                                   {product}   double MaxRAMPercentage                          = 25.000000                           {product}java version "1.8.0_192"Java(TM) SE Runtime Environment (build 1.8.0_192-b12)Java HotSpot(TM) 64-Bit Server VM (build 25.192-b12, mixed mode)

可以看到,JVM 分配的最大 MaxHeapSize 為 16G,計算公式如下:

MaxHeapSize = MaxRAM * 1 / MaxRAMFraction

MaxRAMFraction 預設是4,意味著,每個 JVM 最多使用 25% 的機器記憶體。

但是需要注意的是,JVM 實際使用的記憶體會比 heap 記憶體大:

JVM記憶體  = heap 記憶體 + 執行緒stack記憶體 (XSS) * 執行緒數 + 啟動開銷(constant overhead)

預設的 XSS 通常在 256KB 到 1MB,也就是說每個執行緒會分配最少 256K 額外的記憶體, constant overhead 是 JVM 分配的其他記憶體。

我們可以透過 -Xmx 指定最大堆大小。

java -XX:+PrintFlagsFinal -Xmx1g -version | grep -Ei "maxheapsize|maxram"    uintx DefaultMaxRAMFraction                     = 4                                   {product}    uintx MaxHeapSize                              := 1073741824                          {product} uint64_t MaxRAM                                    = 137438953472                        {pd product}    uintx MaxRAMFraction                            = 4                                   {product}   double MaxRAMPercentage                          = 25.000000                           {product}java version "1.8.0_192"Java(TM) SE Runtime Environment (build 1.8.0_192-b12)Java HotSpot(TM) 64-Bit Server VM (build 25.192-b12, mixed mode)

此外,還可以使用 XX:MaxRAM 來指定。

java -XX:+PrintFlagsFinal -XX:MaxRAM=1g -version | grep -Ei

但是指定 -Xmx 或者 MaxRAM 需要了解機器的記憶體,更好的方式是設定 MaxRAMFraction,以下是不同的 Fraction 對應的可用記憶體比例:

+----------------+-------------------+| MaxRAMFraction | % of RAM for heap ||----------------+-------------------||              1 |              100% ||              2 |               50% ||              3 |               33% ||              4 |               25% |+----------------+-------------------+
容器環境的 Java Heap

容器環境,由於 Java 獲取不到容器的記憶體限制,只能獲取到伺服器的配置:

$ docker run --rm alpine free -m             total     used     free   shared  buffers   cachedMem:          1998     1565      432        0        8     1244$ docker run --rm -m 256m alpine free -m             total     used     free   shared  buffers   cachedMem:          1998     1552      445        1        8     1244

這樣容易引起不必要問題,例如限制容器使用100M 記憶體,但是 JVM 根據伺服器配置來分配初始化記憶體,導致 Java 程序超過容器限制被kill掉。為了解決這個問題,可以設定 -Xmx 或者 MaxRAM 來解決,但就想第一部分描述的一樣,這樣太不優雅了!

為了解決這個問題,Java 10 引入了 +UseContainerSupport(預設情況下啟用),透過這個特性,可以使得 JVM 在容器環境分配合理的堆記憶體。並且,在 JDK8U191 版本之後,這個功能引入到了 JDK 8,而 JDK 8 是廣為使用的 JDK 版本。

UseContainerSupport

-XX:+UseContainerSupport 允許 JVM 從主機讀取 cgroup 限制,例如可用的 CPU 和 RAM,並進行相應的配置。這樣當容器超過記憶體限制時,會丟擲OOM異常,而不是殺死容器。

該特性在 Java 8u191+,10 及更高版本上可用。

注意:在191版本後,-XX:{Min|Max}RAMFraction 被棄用,引入了-XX:MaxRAMPercentage,其值介於 0.0 到 100.0 之間,預設值為 25.0。

最佳實踐

拉取最新的 openjdk:8-jre-alpine 作為底包,截止這篇部落格,最新的版本是 212,>191。

docker run -it --rm openjdk:8-jre-alpine java -versionopenjdk version "1.8.0_212"OpenJDK Runtime Environment (IcedTea 3.12.0) (Alpine 8.212.04-r0)OpenJDK 64-Bit Server VM (build 25.212-b04, mixed mode)

我們構建一個基礎映象,dockerfile 如下:

FROM openjdk:8-jre-alpineMAINTAINER jadepengRUN echo "http://mirrors.aliyun.com/alpine/v3.6/main" > /etc/apk/repositories \    && echo "http://mirrors.aliyun.com/alpine/v3.6/community" >> /etc/apk/repositories \    && apk update upgrade \    && apk add --no-cache procps unzip curl bash tzdata \    && ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \    && echo "Asia/Shanghai" > /etc/timezoneRUN apk add --update ttf-dejavu && rm -rf /var/cache/apk/*

在應用的啟動引數,設定 -XX:+UseContainerSupport,設定 -XX:MaxRAMPercentage=75.0,這樣為其他程序(debug、監控)留下足夠的記憶體空間,又不會太浪費 RAM。

17
最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 遠端linux伺服器上安裝oracle