Linux內(nèi)核根據(jù)應(yīng)用程序的要求分配內(nèi)存,通常來說應(yīng)用程序分配了內(nèi)存但是并沒有實(shí)際全部使用,為了提高性能,這部分沒用的內(nèi)存可以留作它用勋桶,這部分內(nèi)存是屬于每個進(jìn)程的,內(nèi)核直接回收利用的話比較麻煩侥猬,所以內(nèi)核采用一種過度分配內(nèi)存(over-commit memory)的辦法來間接利用這部分“空閑”的內(nèi)存例驹,提高整體內(nèi)存的使用效率。
一般來說這樣做沒有問題陵究,但當(dāng)大多數(shù)應(yīng)用程序都消耗完自己的內(nèi)存的時候麻煩就來了眠饮,因?yàn)檫@些應(yīng)用程序的內(nèi)存需求加起來超出了物理內(nèi)存(包括swap)的容量,內(nèi)核(OOM killer)必須殺掉一些進(jìn)程才能騰出空間保障系統(tǒng)正常運(yùn)行铜邮。
用銀行的例子來講可能更容易懂一些仪召,部分人取錢的時候銀行不怕,銀行有足夠的存款應(yīng)付松蒜,當(dāng)全國人民(或者絕大多數(shù))都取錢而且每個人都想把自己錢取完的時候銀行的麻煩就來了扔茅,銀行實(shí)際上是沒有這么多錢給大家取的,就會發(fā)生擠兌現(xiàn)象秸苗。
那么Java是如何獲取到Host的內(nèi)存信息的呢召娜?沒錯就是通過/proc/meminfo來獲取到的。
默認(rèn)情況下惊楼,JVM的Max Heap Size是系統(tǒng)內(nèi)存的1/4玖瘸,假如我們系統(tǒng)是8G秸讹,那么JVM將的默認(rèn)Heap≈2G。
Docker通過CGroups完成的是對內(nèi)存的限制雅倒,而/proc目錄是已只讀形式掛載到容器中的璃诀,由于默認(rèn)情況下Java壓根就看不見CGroups的限制的內(nèi)存大小,而默認(rèn)使用/proc/meminfo中的信息作為內(nèi)存信息進(jìn)行啟動蔑匣,
這種不兼容情況會導(dǎo)致劣欢,如果容器分配的內(nèi)存小于JVM的內(nèi)存,JVM進(jìn)程會被理解殺死裁良。
一種方法解決 JVM 內(nèi)存超限的問題凿将,這種方法可以讓 JVM 自動感知 docker 容器的 cgroup 限制,從而動態(tài)的調(diào)整堆內(nèi)存大小价脾。
將 Dockerfile 中啟動命令參數(shù)的-Xmx256m替換為-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap牧抵,提交再次運(yùn)行流水線進(jìn)行構(gòu)建部署。
服務(wù)部署成功后彼棍,內(nèi)存上升到一定程度后灭忠,JVM 拋出了 OOM 錯誤,沒有繼續(xù)申請堆內(nèi)存座硕,看來這種方式也是有效果的弛作。
不過,仔細(xì)觀察容器的內(nèi)存占用情況华匾,可以發(fā)現(xiàn)容器所使用的內(nèi)存僅為不到 300M映琳,而我們對于這個容器的內(nèi)存配額限制為 512M,也就是還有 200M+ 是閑置的蜘拉,并不會被 JVM 利用萨西。這個利用率,比起上文中直接設(shè)置-Xmx256m的內(nèi)存利用率要低 旭旭。
推測是因?yàn)?JVM 并不會感知到自己是部署在一個 docker 容器里的谎脯,所以它把當(dāng)前的環(huán)境當(dāng)成一個物理內(nèi)存只有 512M 的物理機(jī),按照比例來限制自己的最大堆內(nèi)存持寄,另一部分就被閑置了源梭。
如此看來,如果想要充分利用自己的服務(wù)器資源稍味,還是得多花一點(diǎn)功夫废麻,手動調(diào)整好-Xmx參數(shù)。
新問題:-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap后模庐,docker沒有被kill了烛愧,但fullGC很平凡,cpu大量占用在垃圾回收的工作上了。
原因:默認(rèn)的xmx的值為鏡像上限內(nèi)存的1/4怜姿,提前fullGC慎冤。導(dǎo)致內(nèi)存的使用率不高。
docker常見退出碼
https://www.cnblogs.com/ainimore/p/12972806.html
如何防止Java超出容器內(nèi)存限制沧卢?
https://www.coder.work/article/1413306
如何設(shè)置Docker容器中Java應(yīng)用的內(nèi)存限制
https://www.cnblogs.com/ilinuxer/p/6648681.html
Docker環(huán)境下Java應(yīng)用的JVM設(shè)置
https://www.cnblogs.com/duanxz/p/10248762.html
在 Docker 里跑 Java粪薛,趟坑總結(jié)
https://my.oschina.net/shisuyun/blog/871514
容器中的JVM資源該如何被安全的限制?
https://www.kubernetes.org.cn/5005.html
如何防止Java超出容器內(nèi)存限制搏恤?
https://stackoom.com/question/3WMDz/%E5%A6%82%E4%BD%95%E9%98%B2%E6%AD%A2Java%E8%B6%85%E5%87%BA%E5%AE%B9%E5%99%A8%E5%86%85%E5%AD%98%E9%99%90%E5%88%B6