在容器內運行JVM時內存的問題


本文內容來自redhat某個人的文章

首先聲明了一個事實,docker容器的-m,kubernets的-limits都可以用來限制內存。當進程使用的內存超過限制時,會收到內核發來的KILL信號。但是JVM完全不知道自己運行在容器內。

那么就有了一個問題“JVM內存超過容器限制的內存會怎樣”。

作者做了一個實驗,實驗流程如下。使用如下命令啟動了一個jboss的wildfly服務器,內存限制是50m

docker run -it –name mywildfly -m=50m jboss/wildfly
docker state 顯示的信息如下

但是在一會后,Wildfly容器執行被中斷,然后打印出信息如下

*** JBossAS process (55) received KILL signal ***
執行 docker inspect mywildfly -f ‘{{json .State}}' 查看容器信息

注意到 OOMKilled=true

 

 然后作者又做了另外一個樣例。使用springboot開接口生成字符串。(啟動參數加上 -XX:+PrintFlagsFinal )

docker run -it --rm --name mycontainer150 -p 8080:8080 -m 150M rafabene/java-container:openjdk

然后發生一個神奇的現象,-m=150m,但是JVM最大內存卻到了241.7MB,內存使用219.8MB。

倆個問題。

1.為什么最大內存是241.7MB

2.-m=150M,為什么允許Java內存到220MB?

根據JVM9的自動設置參數文檔,最大堆內存表示物理內存的四分之一。因為JVM感知不到容器的存在,所以會使用宿主機的信息來計算,如下查看參數信息

docker logs mycontainer150|grep -i MaxHeapSize
uintx MaxHeapSize := 262144000 {product}

-m150m,為什么Java能開到220MB?根據Docker文檔,-m150m表示限制物理內存150M和150M虛擬內存。所以,倆個加起來總共是300M。這就是Java沒有收到Kill的原因。

回到剛開始的問題。“JVM內存超過容器限制的內存會怎樣”。會被Kill掉,那么如何讓JVM感知到容器內存的限制?

解決方案:

使用 fabric8/java-jboss-openjdk8-jdk 鏡像(此鏡像已經廢棄,最新的是這個),意思是這個鏡像會使用腳本計算容器的限制,並且只使用可用內存的百分之50。

  注意:是百分之50,剛好是物理內存的限制,這樣JVM是最優的,沒有內存頁被交換到磁盤。

Dockerfile如下

FROM fabric8/java-jboss-openjdk8-jdk:1.4.0

ENV JAVA_APP_JAR java-container.jar
ENV AB_OFF true

EXPOSE 8080

ADD target/$JAVA_APP_JAR /deployments/

 

下面是Java9的解決方案。

如果你使用Java9,你可以顯示設置JVM參數,-XX:+UnlockExperimentalVMOptions ,-XX:+UseCGroupMemoryLimitForHeap  來讓JVM自動配置讀取到CGgroups的真實內存值。

  注意:此時還是使用物理內存值的四分之一。

$ docker run -d --name mycontainer8g-jdk9 -p 8080:8080 -m 600M rafabene/java-container:openjdk-cgroup

$ docker logs mycontainer8g-jdk9|grep MaxHeapSize
size_t MaxHeapSize = 157286400 {product} {ergonomic}

 

下面是Java10的解決方案。

如果你使用Java10自動解決了這個,能自動感知到運行在容器內。那么-XX:+UnlockExperimentalVMOptions ,-XX:+UseCGroupMemoryLimitForHeap 這倆個參數就可以不要了。

如果加上這個參數,會看到如下警告

Option UseCGroupMemoryLimitForHeap was deprecated in version 10.0 and will likely be removed in a future release.
$ docker run -it --name mycontainer -p 8080:8080 -m 600M rafabene/java-container:openjdk10

 

                原文鏈接

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM