JVM的内存占用

工程 | Andy Wilkinson | 2019年3月11日 | ...

JVM可能是一个复杂的系统。幸运的是,大部分复杂性都隐藏在底层,作为应用程序开发人员和部署人员,我们通常不必过多担心。随着基于容器的部署策略的兴起,一个需要关注的复杂性领域是JVM的内存占用。

两种内存

JVM将其内存分为两大类:堆内存和非堆内存。堆内存是人们通常最熟悉的部分。它存储应用程序创建的对象。它们保留在那里,直到不再被引用并被垃圾收集。通常,应用程序使用的堆大小会随着当前负载而波动。

JVM的非堆内存被划分为几个不同的区域。我们可以使用HotSpot VM的本地内存跟踪 (NMT)来检查其在这些区域的内存使用情况。请注意,虽然NMT不会跟踪所有本地内存使用情况(例如,它不会跟踪第三方本地代码的内存分配),但对于大多数典型的Spring应用程序来说已经足够了。可以使用-XX:NativeMemoryTracking=summary启动应用程序,然后使用jcmd <pid> VM.native_memory summary显示内存使用情况摘要。

让我们通过查看一个应用程序(在本例中是我们的老朋友Petclinic)来说明NMT的使用。下面的饼图显示了NMT报告的JVM内存使用情况(减去其自身的开销),当使用48MB最大堆(-Xmx48M)启动Petclinic时。

正如您所看到的,非堆内存占JVM内存使用的大部分,堆内存仅占总内存的六分之一。在本例中,它大约是44MB(其中33MB是在垃圾收集后立即使用的)。非堆内存总使用量为223MB。

本地内存区域

  • 压缩类空间:用于存储已加载类的信息。受MaxMetaspaceSize限制。已加载类的数量的函数。
  • 线程:JVM中线程使用的内存。正在运行的线程数量的函数。
  • 代码缓存:JIT用于存储其输出的内存。已加载类的数量的函数。受ReservedCodeCacheSize限制。可以通过调整JIT来减少,例如,禁用分层编译。
  • GC:存储GC使用的数据。根据使用的垃圾收集器而有所不同。
  • 符号:存储符号,例如字段名称、方法签名和内部字符串。过多的符号内存使用可能是字符串过于积极地进行内部化的一个指标。
  • 内部:存储不适合其他任何区域的其他内部数据。

区别

与堆内存相比,非堆内存在负载下的变化较小。一旦应用程序加载了它将使用的所有类并且JIT完全预热后,事情就会稳定下来。要减少压缩类空间的使用,需要垃圾收集加载类的类加载器。这在过去更常见,当时应用程序部署到servlet容器或应用程序服务器时——应用程序的类加载器会在应用程序卸载时被垃圾收集——但在现代应用程序部署方法中很少发生。

JVM大小调整

配置JVM以有效利用给定数量的可用RAM并非易事。如果您使用-Xmx16M启动JVM并期望它最多使用16MB的RAM,那么您将面临一个令人不快的意外。

JVM大小调整的一个有趣领域是JIT的代码缓存。默认情况下,HotSpot JVM将使用最多240MB。如果代码缓存太小,JIT将耗尽空间来存储其输出,从而导致性能下降。如果缓存太大,则可能会浪费内存。调整代码缓存大小时,务必查看其对应用程序内存使用量和性能的影响。

在Docker容器中运行时,最新版本的Java现在能够感知容器的内存限制并尝试相应地调整JVM大小。不幸的是,这种大小调整通常会过度分配非堆内存并低估堆内存。假设您有一个在具有2个CPU和512MB可用内存的容器中运行的应用程序。您希望它能够处理更多负载,因此您将CPU加倍到4个,内存加倍到1GB。正如我们上面讨论的那样,堆使用量通常取决于负载,而非堆使用量则少得多。因此,我们希望将大部分额外的512MB内存分配给堆以应对增加的负载。不幸的是,JVM默认情况下不会这样做,它会将其额外内存更平均地分配到堆和非堆区域。

值得庆幸的是,CloudFoundry团队拥有丰富的关于JVM内存占用的知识。如果您正在将应用程序推送到CloudFoundry,则构建包将自动为您应用此知识。如果您没有使用CloudFoudry,或者您想了解更多关于如何调整JVM大小的信息,则设计文档(关于第三版Java构建包内存计算器)提供了一些强烈推荐的进一步阅读材料。

这对Spring意味着什么?

Spring团队花费大量时间思考性能和内存利用率,同时考虑堆和非堆内存使用情况。限制非堆内存使用的一种方法是使框架的某些部分尽可能通用。一个例子是使用反射来创建和注入应用程序bean的依赖项。由于使用了反射,无论应用程序包含多少bean,使用的框架代码量都保持不变。我们使用基于堆的缓存来优化启动时间,并在启动完成后清除此缓存。然后,垃圾收集器可以轻松地回收堆内存,从而使应用程序在处理其工作负载时尽可能多地使用内存。

获取Spring简报

通过Spring简报保持联系

订阅

领先一步

VMware提供培训和认证,以加速您的进步。

了解更多

获取支持

Tanzu Spring在一个简单的订阅中提供对OpenJDK™、Spring和Apache Tomcat®的支持和二进制文件。

了解更多

即将举行的活动

查看Spring社区中所有即将举行的活动。

查看全部