此次部署在k8s集群中的SpringBoot项目OOMKilled问题汇总

现象1:在执行任务时,在页面上发现任务执行失败了(SprintBoot项目)

# kubectl get pod |grep podname  发现有重启的记录

#kubectl describe pod podname  发现Reason:OOMKilled,Exit Code:137

此次部署在k8s集群中的SpringBoot项目OOMKilled问题汇总_第1张图片

经过测试发现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内存占用

此次部署在k8s集群中的SpringBoot项目OOMKilled问题汇总_第2张图片

jvm堆情况

此次部署在k8s集群中的SpringBoot项目OOMKilled问题汇总_第3张图片

疑问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的内存却没有下降。

此次部署在k8s集群中的SpringBoot项目OOMKilled问题汇总_第4张图片

 单单对于现象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

此篇告一段落,欢迎大佬们指出不对的地方

 

转载于:https://www.cnblogs.com/ynx01/p/10762886.html

你可能感兴趣的:(此次部署在k8s集群中的SpringBoot项目OOMKilled问题汇总)