我在C中编写了一个库,它消耗了大量的内存(数百万个小块)。我写了一个使用这个库的程序。我写了一个使用相同库的java程序。 Java程序是库周围非常薄的层。基本上只有一个本地方法被调用,所有的工作都会在几个小时之后完成。使用java调用接口,Java和本机库之间没有进一步的通信。也没有Java对象占用了大量的内存。
所以c程序和Java程序非常相似。整个计算/内存分配发生在本机库中。仍然。执行时,c程序消耗3GB内存。但Java程序消耗4.3GB! (顶部报告的VIRT金额)
我检查了Java进程的内存映射(使用pmap)。图书馆只使用40MB。因此,Java加载的其他库不是原因。
有没有人对此行为有解释?
编辑:感谢您的回答。为了使它更清晰:java代码除了调用本机库 ONCE 之外什么都不做! java堆是标准大小(可能是60MB)并且未使用(除了包含main方法的一个类和调用本机库的另一个类)。
本机库方法是一个长期运行的方法,可以执行大量的malloc和frees。碎片化也是我自己想到的一种解释。但由于没有Java代码处于活动状态,因此Java程序和c程序的碎片行为应该相同。由于它不同,我还假设在c程序或Java程序中运行时使用的malloc实现是不同的。
答案 0 :(得分:3)
猜测:在JVM中运行时,您可能正在使用非默认的malloc
实现,该JVM会调整JVM的特定需求并产生比通用malloc
更多的开销。正常的libc实现。
答案 1 :(得分:2)
对不起伙计们。错误的假设。
我习惯了Sun Java实现用于默认最大堆大小的64MB。但我使用openjdk 1.6进行测试。如果没有明确指定最大堆大小,Openjdk将使用一小部分物理内存。在我的情况下四分之一。我用了一台4GB的机器。因此四分之一是1GB。它是C和Java之间的区别。
可悲的是,此行为未在任何地方记录。我发现它查看了openjdk(arguments.cpp
)的源代码:
// If the maximum heap size has not been set with -Xmx,
// then set it as fraction of the size of physical memory,
// respecting the maximum and minimum sizes of the heap.
答案 2 :(得分:1)
Java需要为其堆提供连续内存,以便它可以将最大内存大小分配为虚拟内存。但是,这不会消耗物理内存,甚至可能不会消耗交换。我会检查你的居民记忆增加了多少。
答案 3 :(得分:0)
您需要考虑不同的因素,特别是在Java等语言上,Java在虚拟机上运行,垃圾收集由Java Runtime处理,因为我需要付出相当大的努力(我想到) Java调用接口用于在本机库中切换或执行本机方法,因为必须有一种方法来在堆栈上分配空间,切换到本机代码,执行本机方法,切换回Java虚拟机,也许某种程度上,堆栈上的空间没有被释放 - 这就是我倾向于想到的。
希望这有帮助, 最好的祝福, 汤姆。
答案 4 :(得分:0)
很难说,但我认为问题的核心是应用程序中有两个需要维护的堆 - 用于Java对象分配的标准Java堆(由JVM维护),以及通过调用malloc / free维护的C堆。如果没有看到一些代码,很难说是什么。
答案 5 :(得分:0)
这是打击它的建议。
使用标准malloc调用停止C代码,并使用通过mmap
/dev/zero
抓取内存的备用malloc版本。你可以从库中修改malloc的实现,或者如果你觉得有足够的能力就可以自己动手。
我强烈怀疑你会发现你的问题在你这样做之后就消失了。