現象1:在執行任務時,在頁面上發現任務執行失敗了(SprintBoot項目)
# kubectl get pod |grep podname 發現有重啟的記錄
#kubectl describe pod podname 發現Reason:OOMKilled,Exit Code:137
經過測試發現OOMKill的時候pod占用的內存非常接近上圖的Limits memory限制的1230Mi。
現象2:pod從啟動到OOM期間內存一直增長未下降過,jvm初始聲明的堆空間為1.7G,運行期間EdenGen占用越來越大(增長速度比較快)直到占滿觸發GC,GC之后Eden Space增大了100M,old sapce大小和占用沒有變化,這過程中pod內存占用沒有受到GC的影響(一直緩慢增長)。后面Eden空間占用繼續升高在還未再次觸發GC的時候,OOMKill,pod重啟了。
#kubectl top pod |grep podname 查看pod內存占用
jvm堆情況
疑問1:pod啟動之后jvm就給堆分配了1.7G的空間,容器限制內存為1230MI,同時pod剛運行時占用的內存為900多M。那么pod占用的900M是哪些地方占用的,jvm分配的堆和實際占用的不是一樣大的么?
假設這里的1.7G只是聲明,並沒有實際占用這么多。
疑問2:執行任務期間JVM堆中Eden空間占用在不斷增長(速度較快),但是pod的內存占用增長的速度遠比Eden空間占用增長慢,隨着Eden空間占滿觸發 Minor GC(從年輕代空間(包括 Eden 和 Survivor 區域)回收內存)Eden空間內存回收,這里從占滿1個G到63M,Pod的內存卻沒有下降。
單單對於現象2有找到一個解釋(地址:https://stackoverflow.com/questions/54279068/kubernetes-pod-memory-usage-does-not-fall-when-jvm-runs-garbage-collection):
這里的情況和現象2基本一致。
疑問3:GC之后Eden Space擴容了100M,之后還沒到觸發GC,pod占用的內存就超過1230M導致pod重啟了。那么pod實際占用內存由哪些部分組成,JVM占用的內存由哪些部分組成,他們之間的聯系又是怎么樣的?
期間忙別的事去了,這里補充一下:
疑問1:pod啟動之后jvm就給堆分配了1.7G的空間,容器限制內存為1230MI,同時pod剛運行時占用的內存為900多M。那么pod占用的900M是哪些地方占用的,jvm分配的堆和實際占用的不是一樣大的么?
answer:pod啟動后commited內存為物理內存+交換分區,交換分區不占用真正的空間,占用的是磁盤的空間(可以了解一下虛擬內存),針對此問題這里900M是真正使用的物理內存。
疑問2:執行任務期間JVM堆中Eden空間占用在不斷增長(速度較快),但是pod的內存占用增長的速度遠比Eden空間占用增長慢,隨着Eden空間占滿觸發 Minor GC(從年輕代空間(包括 Eden 和 Survivor 區域)回收內存)Eden空間內存回收,這里從占滿1個G到63M,Pod的內存卻沒有下降。
answer:JDK1.8默認GC收集器為Parallel GC,這個回收器在GC之后不會把內存返還給OS(https://www.javacodegeeks.com/2017/11/minimize-java-memory-usage-right-garbage-collector.html),所以GC以后pod內存未下降;
針對pod內存占用增長速度比Eden空間增長慢的現象解釋:Eden空間有一部分已經是在使用物理內存了,當實際占用接近實際分配的內存時,需要更多的內存,jvm從交換分區交換到物理內存,此時進程內存占用才上升
疑問3:GC之后Eden Space擴容了100M,之后還沒到觸發GC,pod占用的內存就超過1230M導致pod重啟了。那么pod實際占用內存由哪些部分組成,JVM占用的內存由哪些部分組成,他們之間的聯系又是怎么樣的?
answer:jvm會根據內存使用情況動態調整內存大小,占用較高但是未觸發GC時jvm調整內存(擴容或者交換),此時物理內存已經不足了,沒有更多的物理內存可以分配導致OOM。pod實際占用的絕大部分就是java進程占用的物理內存(commited內存=物理內存+交換分區,一般一個pod內部就只有java一個進程),附圖:
圖片復制自:http://www.importnew.com/14486.html
此篇告一段落,歡迎大佬們指出不對的地方