【问题标题】:Java application memory usageJava 应用程序内存使用情况
【发布时间】:2011-03-09 22:15:52
【问题描述】:

我一直在编写一个小型 Java 应用程序(我的第一个!),目前它只做一些事情。目前,它运行 Main 类,它启动一个 gui 类(我编写的一个扩展 JFrame 的类,它只包含一个 JTextArea),一个通过大约 40kb 的 BufferedInputStream 加载本地文件的类,以及从一个加载条目的类Java 属性文件。

一切都很好,但是,我正在查看 Windows 任务管理器,我注意到一些让我感到奇怪的东西。当我启动应用程序时,当它加载本地文件并从中提取一些值以显示在 JTextArea 中时,RAM 使用量跃升至大约 40MB,这对我来说似乎很正常,因为 JVM、Java 基类等。在这个但是,当应用程序完成加载文件时,它只是处于空闲状态,因为我目前没有让它做任何其他事情。当它处于空闲状态时,只要窗口处于活动状态,应用程序的内存使用量就会开始以每秒 10-20kb 的速度攀升。这让我觉得很奇怪。如果我单击另一个程序使该程序成为非活动窗口,内存仍然会增加,但速度要慢得多(大约每 3-5 秒 10kb)。

我还没有测试过它会上升多远,但这让我觉得这是非常奇怪的行为。这是正常的 Java 行为吗?我想我的代码可能会泄漏内存,但我不确定如何。我确实确保关闭了我正在使用的 BufferedInputStream,但我看不出还有什么会导致这种情况。

如果我的解释没有意义,我很抱歉,但我希望任何人有任何见解和/或指点。

更新:

根据建议,我基本上将我的应用程序剥离到 Main 类,它只是调用 gui 类。 gui 类仅扩展 JFrame 并设置窗口大小、关闭操作和可见属性。通过这些更改,内存仍以 10-20kb 的速度增长,但速度较慢。这与我收到的其他建议一起使我相信这只是 Java。我会继续玩它,如果我发现其他有趣的东西,我会告诉大家。

【问题讨论】:

  • 恭喜你的第一个应用程序!!!也许你可以发布一些代码?没有代码,我们只是猜测。也只需继续监控它,看看它是否真的一直在上升,或者它是否只是在某个时候停止。发布你的结果。
  • @Romain,谢谢!我考虑过发布我的代码,但老实说,我更感兴趣的是看看这是否是某种正常的 Java 行为(我不这么认为,但一切皆有可能!)。如果几天后我无法弄清楚原因,我将进行更多调查,然后发布代码。谢谢!
  • #masternosaj 当内部刷新到屏幕并完成垃圾收集时,内存会有一些波动是正常的。内存不断增长是不正常的。如果您是 Java 初学者,我看到有人要求对本网站上的代码部分进行代码审查。
  • @Romain,现在这让我感觉好多了,这很有意义,而且屏幕刷新等等。感谢您的洞察力!

标签: java memory memory-leaks


【解决方案1】:

尝试使用 jconsole 而不是 Windows 任务管理器监控堆使用情况:

  • 使用 -Dcom.sun.management.jmxremote 选项启动您的应用程序,例如

java -Dcom.sun.management.jmxremote -jar myapp.jar

  • 从命令行启动jconsole,并连接到您在上一步中启动的java进程的本地pid。
  • 点击内存并查看堆内存(默认显示)

如果您观察一段时间,您可能会在内存随时间攀升时出现“锯齿”模式,但随后在垃圾收集器运行时会急剧下降。您可以尝试通过单击这样标记的按钮来“建议”垃圾收集。

当您执行此操作时,内存使用量是否会下降到相同的最低水平,或者整个最低限度是否会在几分钟内增加?如果最小使用量增加,那么您就有内存泄漏。如果它总是返回到相同的最低水平,那么你很好。

【讨论】:

  • 这是一个非常有见地的答案。我会试试看的!
  • 我尝试了 JConsole,它是一个非常漂亮的实用程序。正如我所看到的,堆内存使用量不断增加。当我调用 GC(使用您提到的按钮)时,内存使用量触底。我尝试了几次,它总是下降到大约相同的最低水平。非常感谢!
  • 请注意,JDK 6 有一个更漂亮的实用程序:JVisualVM。通过在命令提示符中键入命令jvisualvm 来启动它。
  • @Jesper,我也会检查一下。
  • @Jesper 感谢您的指点 - 不知道那个,但它会派上用场,因为我现在正在解决我自己的内存泄漏问题。
【解决方案2】:

恭喜您的第一个应用!现在,有几件事要考虑。首先,Windows 任务管理器不是了解虚拟机增长速度的好资源。相反,您应该在控制台中监控垃圾收集统计信息(使用-verbose:gc 命令行参数)。其次,如果您担心潜在的泄漏和 vm 的增长,这里有很多很棒的分析器,它们易于使用并且可以帮助您诊断内存问题。查看这些two posts 了解一些分析器选项。

【讨论】:

  • @afk,谢谢!我听说 Windows 任务管理器不是监视 Java 应用程序的最佳工具,但我不知道这些信息的可信度如何。我很好地检查了你提到的内容。
【解决方案3】:

祝贺您的第一个 Java 应用程序!

Java 应用程序在虚拟机中运行。操作系统已为虚拟机分配了固定数量的内存,通常为 512 MB。只要应用程序使用少于 512 MB,垃圾收集器就不会启动并开始搜索“死”内存块。 JVM 内存限制可以在大多数操作系统中修改。例如,尝试将内存限制切换为 32 MB。

【讨论】:

  • 谢谢!!我会记住这一点。我将尝试看看它实际上上升了多远。感谢您的建议。
  • 基本上是正确的,但是我遇到的任何 JVM 都不会分配那么大 (512Mb) 的初始堆......除非通过 JVM 启动选项明确告诉它。
【解决方案4】:

这是正常的 Java 行为吗?

没有。

我猜我的代码可能会泄漏内存

这绝对是原因。请发布您的源代码,否则无法进一步诊断。

我注意到您正在使用 Swing,请确保您使用 invokeLater(Runnable) 方法在 event dispatch thread 中启动您的 JFrame

如果您正在使用任何类型的集合,请确保您在完成后clear 他们。

由于您正在进行一些文件 IO,因此请确保在完成后关闭 IO 操作中涉及的所有类。

如果您正在使用任何事件侦听器,请记住在不再需要时显式删除事件侦听器。


您可以尝试的一件事是试验。拿你的应用程序并删除文件 IO,看看会发生什么。内存使用量是否仍然像以前一样攀升?现在将您的应用程序恢复正常,并删除文本区域 - 内存是否仍像以前一样攀升?等等等等。这将帮助您确定来源是什么,并且您可以将精力集中在那里。通过这样做,您很可能会发现自己的目标。

另一个有用的诊断工具是在特定时间点使用System.gc(),通常繁重的代码块之后。这将告诉 JVM 在执行的那个点执行垃圾收集,而不是在由内存消耗决定的另一个时间。这将帮助您考虑应用程序内存使用的任何周期性波动。

如果失败,您可以随时使用内存分析器。如果您使用的是 Netbeans IDE,那么它就内置了一个。对于 Eclipse,有几个插件可以执行分析。

【讨论】:

  • 是的,这是 Java。处理它。
  • @bguiz 我不确定我理解你所说的事件调度线程是什么意思。我对 Java 很陌生,我还没有看到提到过。
  • @masternosaj :在您的public static void main 方法中,不要通过调用构造函数来实例化您的JFrame。相反,在 Runnable 中实例化它并在可运行对象上执行 invokeLater。这通常用于线程,而不是内存泄漏,但无论如何你都应该这样做,因为 Sun 设计 Swing 就是这样使用的。
【解决方案5】:

这很正常。一些背景计算可能会留下死对象,JVM 并不急于清理这些对象。最终,当接近 max mem 时,它们将被垃圾收集。

让你的程序在一夜之间运行,你的机器不会炸毁。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-11
    • 2014-11-08
    • 2015-01-13
    • 1970-01-01
    相关资源
    最近更新 更多