即使是小程序也会出现高Java内存使用问题

39

我有几个用Java编写的简单应用程序,其中一个被写成小部件。令我惊讶的是,即使是小型应用程序也会占用大量RAM。

我编写了以下内容以查看它是否是我的程序中存在的错误或一般的Java问题:

public class ram {
    public static void main(String[] args){
    while(true)System.out.print("Hello World");//while loop to give me time to check RAM usage
    }
}

然后我用java ram编译并运行它,它给出了以下的内存使用情况:

The process java (with pid 4489) is using approximately 43.3 MB of memory.
34460 KB    [heap]
7088 KB /usr/lib/jvm/java-7-openjdk/jre/lib/amd64/server/libjvm.so
1712 KB /usr/lib/jvm/java-7-openjdk/jre/lib/rt.jar
136 KB  [stack:4495]
120 KB  /usr/lib/jvm/java-7-openjdk/jre/lib/amd64/libjava.so

这不是太高了吗?尤其是34MB的堆。我的系统是ArchLinux x86_64和openjdk-7。

有没有办法最小化JVM使用的内存量?

编辑:我尝试使用-Xmx标志,这是我得到的结果(1281k是它让我起步的最小值):

java -Xmx1281k ram
The process java (with pid 4987) is using approximately 27.6 MB of memory.
18388 KB    [heap]

相比之下,Python2使用4.4MB,Mono使用4.3MB。


可能是重复的问题:如何为JVM设置最大内存使用量? - dsgriffin
7
谁在意呢?虚拟内存本质上是免费的。现代系统可以以接近零成本的方式制造大量的虚拟内存。这就像试图少呼吸一样。(需要注意的是,这不是测量物理内存(RAM),而只是测量虚拟内存,即地址空间。) - David Schwartz
43MB并不令人惊讶,因为JVM为可能的未来负载保留了足够的内存。但是,如果您将最大内存设置为几MB,那么应该没问题。 - irreputable
JVM确实使用了[相对]大量的内存。虽然David提到它是“虚拟”的,但我认为这可能会掩盖与典型Java环境相比本地应用程序所涉及的开销(特别是当应用程序“什么也不做”但启动时)-那么这与物理使用相比如何?我不知道.. - user166390
@TomG 有时候问题不在于内存的成本,而是因为某些设备只能支持有限的内存(例如树莓派:265/512MB RAM,我的上网本:2GB)。 - Vivo
显示剩余3条评论
2个回答

118

我经常看到类似的问题,但仍未看到令人满意的答案。

最常见的回答是“你为什么在乎?”的愤怒回答。有些人会花费很多精力来让问题和提问者看起来很愚蠢。

有些人会用长篇大论来回答这个问题,解释Java分配不同类型内存的原因、如何做以及应该查找哪些命令行参数。(很少有人具体说明)

事实上,对于小型应用程序,Java在大多数操作系统上都需要占用大量内存。 程序越小,它就越显而易见。 Java开发人员已经习惯了处理或忽略这个事实。

似乎存在许多看似异常的内存使用原因。 每个线程都会得到一定数量的内存用于其堆栈。 无论程序多么简单,都会启动几个线程进行垃圾清理、远程方法调用等操作。 在Windows / 64位上,每个线程需要1MB的内存。 默认加载一堆类和所有您的类。 我相信其他许多事情都在幕后发生。

Java做出了其他语言没有做出的折衷选择。 加载时间比大多数其他语言慢。 初始内存需求更高。 String作为最常用的数据类型,比大多数人意识到的占用更多内存。 还有无数其他的因素。 在许多情况下,这些选择的好处确实会得到回报。 Hello World这样的程序显示出了这些选择的成本。 像易于多线程和接近本机性能等好处在Hello World中真的没有什么用处。

不幸的是,对于一个简单的应用程序,你真的不能做太多事情来最小化所使用的内存。虽然有上述的命令行开关,试错可能能将报告的使用量缩小到大约10-15mb的水平,但这些选择和你花费在找出它们的时间并不适用于未来各种各样的应用程序。你必须为下一个应用程序再次经历同样的过程。加入 GUI 界面和一些日志记录以及另外一些常见库,你的基本数字很快就会飙升到 60mb。

你没有做错任何事。这只是 Java 中的工作方式。你会习惯它。由于它,你偶尔会选择另一种语言,这也没关系。


23
感谢您抽出时间提供一个平衡的回答,没有任何通常在这两个方向上的激烈情绪。+1 - Basic
1
这是一个很棒的答案。似乎解决了难题。 - bluelurker
4
为什么C#使用的内存较少?例如,我通常看到IntelliJ、Eclipse或NetBeans使用1GB的RAM,但Visual Studio只使用300MB。此外,我还见过其他C#程序,如Paint.Net,根据任务管理器显示它们也只占用极少的内存。 - Pavel
1
@pavel 也许 C# 只在 Windows 上运行时有更好的优化,例如利用系统资源等方面,而 JVM 需要在其他平台上工作,必须实现自己的魔法。不过我可能是错的。 - James Lin
3
谢谢!我得到了最好的答案。其他答案都是“因为新电脑有足够的RAM,所以这并不重要”。我是一名C++程序员,所以这对我来说是一个有趣的话题。真的非常感谢。 - Gabor Szita
显示剩余7条评论

10

这是由于以下几个原因:

  1. Java运行时本身就是一个相当复杂的程序。它需要将您的Java程序的字节码(从javac输出)翻译成所在系统的机器码,还有针对此操作的优化器、调试接口等。
  2. 尽管您的程序相当小,但Java仍会从其标准库中加载许多类。您可以通过使用“java -verbose:class ram”启动来观察这一点。
  3. Java为您的程序预先分配了大量内存 - 它无法知道实际需要多少内存。这受到-Xmx选项等的控制。有几种这种类型的内存。要了解更多信息,您可以使用JDK的bin文件夹中包含的JConsole工具。您可以在java.sun.com上阅读有关它的更多信息。关于Java使用的内存区域的摘要也在这个stackoverflow问题中给出。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接