Java JAR 内存使用 VS 类文件内存使用

标签 java profiling

我最近将我的大型 Java 应用程序更改为以 JAR 而非单个类文件的形式交付。我有 405 个 JARS,其中包含 5000 个类文件。我的问题是,当我将程序作为 JAR 运行时(类路径是获取所有 JAR 的通配符),Java 将不断使用越来越多的内存。我已经看到内存超过 2GB,而且 Java 似乎没有执行停止世界的垃圾收集来降低内存。如果我针对展开的 JAR(仅类文件)运行完全相同的程序,Java 的内存使用率会低得多(< 256MB)并保持在那里。这发生在 Windows 7 (x64) 和 Windows Server (x64) 上的 Oracle Java 8 中。为什么将我的应用程序打包为 JAR 会更改内存配置文件?此外,我已经将程序作为 JAR 运行了很长时间,最大内存限制为 128MB,没有任何问题,所以我没有内存泄漏。

类路径中的 JAR 文件 With JAR files in classpath

类路径中的类文件 With class files in classpath

编辑:我接受了@K Erlandsson 的回答,因为我认为这是最好的解释,而这只是 Java 的一个丑陋的怪癖。感谢大家(尤其是@K Erlandsson)的帮助。

最佳答案

首先要注意的是,堆上完全使用了多少内存在任何时候都不是很有趣,因为使用的大部分内存可能是垃圾,将被下一次 GC 清除。

您需要关注的是 Activity 对象使用了多少堆。您在评论中写道:

I don't know if this matters, but if I use jvisualvm.exe to force a GC (mark sweep) the heap memory usage will drop clearing almost all the heap memory.

这很重要。 很多。这意味着当您在使用 jar 时看到更高的堆使用率时,您会看到更多的垃圾,而不是 Activity 对象消耗的更多内存。当您执行 GC 时垃圾被清除,一切都很好。

从 jar 文件加载类比从类文件加载它们暂时会消耗更多的内存。需要打开、查找和读取 jar 文件。与简单地打开特定的 .class 文件并读取它相比,这需要更多的操作和更多的临时数据。

由于大部分堆使用都被 GC 清除,因此您不需要非常关注这种额外的内存消耗。

你还写:

Java will continually use more and more memory. I have seen the memory go > 2GB and it seems like Java is not doing stop-the-world garbage collections to keep the memory lower.

这是典型的行为。 GC 仅在 JVM 认为有必要时运行。 JVM 将根据内存行为对此进行调整。

编辑:现在我们看到了您的 jConsole 图像,我们看到了提交堆内存的不同(250 MB 与 680 MB)。提交堆是堆的实际大小。这将有所不同(取决于您使用 -Xmx 设置的值),具体取决于 JVM 认为将为您的应用程序产生最佳性能的内容。但是,它主要会增加,几乎不会减少。

对于 jar 情况,JVM 已为您的应用程序分配了更大的堆。可能是由于在初始类加载期间需要更多内存。 JVM 然后认为更大的堆会更快。

当您拥有更大的堆、更多的提交内存时,在运行 GC 之前有更多的内存可供使用。这就是为什么您会看到两种情况下内存使用情况的差异。

底线:您看到的所有额外使用都是垃圾,而不是 Activity 对象,为什么您不需要担心这种行为,除非您有实际问题,因为内存将在下一次 GC。

关于Java JAR 内存使用 VS 类文件内存使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31079320/

相关文章:

java - RxJava - 何时将 Observable 与创建方法一起使用

java - 调用类的不同实现

java - Java 程序中的下载有时会损坏

c++ - 使用 C++ 在 Linux 中计算磁盘读写

java - 监控每个线程的内存使用情况

java - 为什么 "customised Enum constructor"返回所有其他 Enum 类型的信息?

java - 错误: Could not find or load main class error when compiling in eclipse and command prompt But works in intelliJIDEA

haskell - Cabal 在需要分析库时没有安装依赖项?

java - 如何使用 java -prof 选项获取在 Tomcat 上运行的 java 程序的分析输出?

f# - 为递归函数的性能分析 F#