如何监控Java内存使用情况?

Ole*_*liv 60 java monitoring garbage-collection memory-management

我们在Jboss上运行了一个j2ee应用程序,我们希望监视它的内存使用情况.目前我们使用以下代码

    System.gc();
    Runtime rt = Runtime.getRuntime();
    long usedMB = (rt.totalMemory() - rt.freeMemory()) / 1024 / 1024;
    logger.information(this, "memory usage" + usedMB);
Run Code Online (Sandbox Code Playgroud)

这段代码工作正常.这意味着它显示了与现实相对应的记忆曲线.当我们从DB创建一个大的xml文件时,曲线会上升,在提取完成后,它会下降.

替代文字

一位顾问告诉我们,明确调用gc()是错误的,"让jvm决定何时运行gc".基本上他的论点与此处讨论的相同.但我还是不明白:

  • 我怎么能有我的记忆力使用曲线?
  • 显式gc()有什么问题?我不关心使用显式gc()可能发生的小的性能问题,我估计会在1-3%.我需要的是内存和线程监视器,它可以帮助我分析我们在客户站点上的系统.

ami*_*efr 52

如果你想真正了解VM内存中发生的事情,你应该使用像VisualVM这样的好工具.这个软件是免费的,这是一个很好的方式来看看发生了什么.

使用显式gc()调用没有什么是"错误的".但是,请记住,当您调用gc()时,您"建议"垃圾收集器运行.无法保证它会在您运行该命令的确切时间运行.

  • VM有一个-XX:+ DisableExplicitGC选项的原因!问题不在于调用GC一定不好.但是如果你经常调用GC*会很糟糕*.当大多数算法不会阻止整个VM执行完整的GC时,它可能会导致完整的GC.如果您正在运行HUGE,这可能会特别成问题,整个VM可能会暂停几分钟.如果发生这种情况,您可以告诫其他操作超时(如数据库连接,rmi连接等) (11认同)
  • System.gc()可能会损害性能,因为它会干扰GC的算法.这会降低所有后续GC. (4认同)
  • [引证需要]注意证明你的主张?请解释如何使用垃圾收集器算法调用gc()"干扰"以及如何调用方法"降低"后续调用? (3认同)
  • 刚刚在研究 VisualVM - 它很不错。 (2认同)

Mr.*_* 安宇 28

有一些工具可以让您监控VM的内存使用情况.该VM可以公开使用JMX内存统计信息.您还可以打印GC统计信息以查看内存随时间的变化情况.

调用System.gc()可能会损害GC的性能,因为对象会过早地从新代移到旧代,弱引用会过早清除.这可能导致内存效率降低,GC时间延长,缓存命中率降低(对于使用弱refs的缓存).我同意你的顾问:System.gc()很糟糕.我会使用命令行开关禁用它.

  • +1对于过早晋升的优秀评论. (2认同)

Fel*_*lix 10

你可以看一下stagemonitor.它是一个开源的Java(Web)应用程序性能监视器.它捕获响应时间指标,JVM指标,请求详细信息(包括请求探查器捕获的调用堆栈)等.开销很低.

或者,您可以使用伟大的时间序列数据库石墨来存储数据点的长历史,您可以使用花哨的仪表板查看这些数据点.

例: JVM内存仪表板

查看项目网站,查看截图,功能描述和文档.

注意:我是stagemonitor的开发者


Yis*_*hai 9

我会说顾问在理论上是正确的,你在实践中是正确的.正如俗话说:

理论上,理论和实践是相同的.实际上,他们不是.

Java规范说System.gc建议调用垃圾收集.实际上,它只是生成一个线程并立即在Sun JVM上运行.

虽然理论上你可能搞乱了一些精心调整的垃圾收集JVM实现,除非你编写的是旨在部署在任何JVM上的通用代码,不要担心它.如果它适合你,那就去做吧.


Nic*_*olt 5

看看JVM args:http://java.sun.com/javase/technologies/hotspot/vmoptions.jsp#DebuggingOptions

XX:-PrintGC在垃圾收集中打印消息.管理.

-XX:-PrintGCDetails在垃圾收集中打印更多细节.管理.(在1.4.0中引入.)

-XX:-PrintGCTimeStamps打印垃圾回收时的时间戳.可管理(1.4.0中引入)

-XX:-PrintTenuringDistribution打印终身年龄信息.

虽然您不打算通过显式调用来破坏JVM,System.gc()但它们可能没有您期望的效果.要真正理解JVM中的内存发生了什么,读取Brian Goetz所写的任何内容和所有内容.


Ste*_* B. 5

在生产系统上显式运行System.gc()是一个糟糕的主意.如果内存达到任何大小,整个系统可以在完整GC运行时冻结.在一个千兆字节大小的服务器上,这很容易非常明显,这取决于如何配置jvm,它有多少空间等等 - 我已经看到超过30秒的暂停.

另一个问题是,通过显式调用GC你实际上并没有监视JVM如何运行GC,你实际上是在改变它 - 取决于你如何配置JVM,它会在适当的时候进行垃圾收集,并且通常会逐步进行(它不会在内存不足时运行完整的GC).你将要打印出来的内容与JVM独自完成的内容完全不同 - 一方面,你可能会看到更少的自动/增量GC,因为你将手动清除内存.

正如尼克霍尔特的帖子指出的那样,打印GC活动的选项已经作为JVM标志存在.

你可以有一个线程,只需要以合理的间隔打印出免费和可用的线程,这将显示实际的mem使用情况.


Pab*_*jim 5

如果您喜欢从命令行执行此操作的好方法,请使用 jstat:

http://java.sun.com/j2se/1.5.0/docs/tooldocs/share/jstat.html

它以可配置的时间间隔提供原始信息,这对于记录和绘图目的非常有用。