Java 内存分析:如何检测哪个应用程序/包占用了太多内存

Java 内存分析:如何检测哪个应用程序/包占用了太多内存,java,jakarta-ee,memory-leaks,profiling,memory-management,Java,Jakarta Ee,Memory Leaks,Profiling,Memory Management,我在工作中遇到过这样一种情况:我们运行一个JavaEE服务器,上面部署了几个应用程序。最近,我们经常发生OutOfMemoryException。我们怀疑一些应用程序可能表现不好,可能是泄漏或其他什么 问题是,我们真的不知道是哪一个。我们已经运行了一些内存分析器(比如YourKit),它们非常擅长判断哪些类使用的内存最多。但是它们没有显示类之间的关系,所以这就给我们留下了这样一种情况:我们看到,比如说,有很多字符串、int数组和HashMap条目,但我们无法真正区分它们来自哪个应用程序或包 有没

我在工作中遇到过这样一种情况:我们运行一个JavaEE服务器,上面部署了几个应用程序。最近,我们经常发生OutOfMemoryException。我们怀疑一些应用程序可能表现不好,可能是泄漏或其他什么

问题是,我们真的不知道是哪一个。我们已经运行了一些内存分析器(比如YourKit),它们非常擅长判断哪些类使用的内存最多。但是它们没有显示类之间的关系,所以这就给我们留下了这样一种情况:我们看到,比如说,有很多字符串、int数组和HashMap条目,但我们无法真正区分它们来自哪个应用程序或包


有没有一种方法可以知道这些对象来自何处,这样我们就可以确定分配了最多内存的包(或应用程序)?

一个简单的想法是,如果您不介意一些性能折衷的话,您可能可以做些反思……

在这种情况下可以做几件事:

  • 。从1.5天开始,通过JVM参数可以使用此功能。获得转储后,可以使用以下工具对其进行脱机分析:。重要的部分是找出支配树
  • 在测试服务器上执行内存分析;他擅长这个。在分析根本原因时,这肯定比第一次需要更多的时间,因为必须存在内存分配失败的确切情况。如果您有自动集成/功能测试,那么推断根本原因将更容易。诀窍是定期进行堆转储,并分析导致堆消耗增加的类。可能不一定存在泄漏-可能是堆大小不足的情况

    • 我发现有帮助的是:

      jmap -J-d64 -histo $PID
      
      (删除32位arch的
      -J-d64
      选项)

      这将输出如下内容:

      num     #instances         #bytes  class name
      ----------------------------------------------
      1:       4040792     6446686072  [B
      2:       3420444     1614800480  [C
      3:       3365261      701539904  [I
      4:       7109024      227488768  java.lang.ThreadLocal$ThreadLocalMap$Entry
      5:       6659946      159838704  java.util.concurrent.locks.ReentrantReadWriteLock$Sync$HoldCounter
      
      然后,您可以尝试进一步诊断问题,进行差异分析,以及不比较连续快照的内容


      这只会使虚拟机暂停一小段时间,即使是在大堆的情况下,这样您就可以在生产中安全地执行此操作(在非高峰时间,希望是:)

      您是否已将探查器连接到各个应用程序?或者只是到应用服务器?你有办法在测试服务器上拆分它们吗。。给每个人一个较小的最大堆。。。观察哪一个会爆炸?您还可以启用GC日志并查看堆的新旧区域的大小。使用“-verbose:gc-XX:+PrintGCDetails XX:+PrintGCTimeStamps–Xloggc:PATH_FROM_ROOT/gclog.log”为starters@JeffStorey:我们已经将探查器(YourKit和JRockit任务控制)连接到JVM本身。如何将探查器附加到应用服务器中的特定应用?这当然会有所帮助@bwawok:是的,我们也考虑过这个选项,尽管它需要一些设置和校准:我们不知道我们的应用程序需要多少内存(即使表现良好)@josek:我们现在正在启用gc日志,尽管我们没有分析它们的经验。@malvim。当它们都在运行时,将它们连接到应用服务器可能会很困难。您可以在应用服务器上一次运行一个,然后连接到应用服务器吗?或者如果您在本地计算机上(您不能远程执行堆转储),只运行
      jvisualvm