JVM堆内存设置与实际内存占用的差异

Java程序的实际占用内存不一定大于其设置的-Xms

通过k8s容器部署的一个Java应用设置了JVM参数-Xms 2048M -Xmx-2048M -Xmn 1024M,这里先不论这个设置在这个线上实际场景是否合理的问题。但通过k8s监控看到这个容器实际内存占用大约是1.8G,进入到容器使用jcmd/jmap看堆内存使用也是低于2G,大约是800多M。在JVM进程启动时,操作系统会参照JVM参数分配相应的虚拟内存给进程、一般显示为virt或vss ,而实际内存占用体现在进程真正使用的物理内存页也就是物理内存,一般显示为rss。

虚拟内存

虚拟内存简单理解是个虚拟的逻辑的内存空间,操作系统把除了真正的物理内存之外、还可能包括需要的一些磁盘文件之类的,统一映射到一张寻址表或者内存空间里,来统一进行资源调度使用。

JVM堆内存保持

JVM一般会保持从系统得到的物理内存,而不主动释放给系统。垃圾回收只是主动管理自己保持的这些内存中的堆内存、区分一下哪些是实际使用哪些是可用的,也就是说一次GC可能会使得堆内存中已用降低而可用增加,而不会在系统视角上使得该进程所占用内存降低。这是一种策略,尝试避免反复向系统进行内存申请的开销。
但具体问题要具体处理,如果确实对内存资源比较敏感的情况,比如容器环境,那可以通过类似如下方法进行配置:

# 允许更积极的堆收缩,限制元空间增长
java -Xms512m -Xmx4g \
     -XX:MinHeapFreeRatio=20 \      # 空闲低于 20% 时扩展堆
     -XX:MaxHeapFreeRatio=40 \      # 空闲高于 40% 时收缩堆
     -XX:MaxMetaspaceSize=256m \    # 限制元空间
     -XX:+UseG1GC                  # 推荐 G1(对堆收缩更友好)

而如果资源充足,且想避免内存释放与申请带来的延迟,那么可以采用类似配置:

# 固定堆大小,避免动态调整带来的 GC 停顿
java -Xms4g -Xmx4g \     # 堆固定为 4G
     -XX:+UseParallelGC  # 高吞吐量 GC
参考

https://blog.csdn.net/nullbull/article/details/108670344
https://stackoverflow.com/questions/12108706/why-does-the-jvm-consume-less-memory-than-xms-specified
https://serverfault.com/questions/138427/what-does-virtual-memory-size-in-top-mean

posted on 2025-03-29 18:48  肥兔子爱豆畜子  阅读(167)  评论(0)    收藏  举报

导航