Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么本机库在java使用时使用的内存是linux下C程序使用时的1.5倍?_Java_Linux_Memory_Native - Fatal编程技术网

为什么本机库在java使用时使用的内存是linux下C程序使用时的1.5倍?

为什么本机库在java使用时使用的内存是linux下C程序使用时的1.5倍?,java,linux,memory,native,Java,Linux,Memory,Native,我用C编写了一个库,它消耗了大量内存(数百万个小块)。我已经编写了一个使用这个库的c程序。我已经编写了一个java程序,它使用相同的库。Java程序是围绕库的一个非常薄的层。基本上只有一个本机方法被调用,完成所有工作并在数小时后返回。Java和使用Java调用接口的本机库之间没有进一步的通信。也不存在消耗大量内存的Java对象 所以c程序和Java程序非常相似。整个计算/内存分配发生在本机库中。还是。执行c程序时会消耗3GB内存。但是Java程序消耗了4.3GB!(top报告的VIRT金额) 我

我用C编写了一个库,它消耗了大量内存(数百万个小块)。我已经编写了一个使用这个库的c程序。我已经编写了一个java程序,它使用相同的库。Java程序是围绕库的一个非常薄的层。基本上只有一个本机方法被调用,完成所有工作并在数小时后返回。Java和使用Java调用接口的本机库之间没有进一步的通信。也不存在消耗大量内存的Java对象

所以c程序和Java程序非常相似。整个计算/内存分配发生在本机库中。还是。执行c程序时会消耗3GB内存。但是Java程序消耗了4.3GB!(top报告的VIRT金额)

我检查了Java进程的内存映射(使用pmap)。库仅使用40MB。因此,Java加载的附加库不是原因

有人对这种行为有什么解释吗

编辑:感谢您迄今为止的回答。更清楚一点:java代码只调用本机库一次!java堆是标准大小(可能是60MB),没有使用(除了一个包含main方法的类和另一个调用本机库的类)


本机库方法是一种长期运行的方法,可以执行大量mallocs和free操作。碎片化也是我对自己的一种解释。但是由于没有活动的Java代码,Java程序和c程序的碎片行为应该是相同的。由于它是不同的,我还假设在c程序或Java程序中运行时使用的malloc实现是不同的。

有不同的因素需要考虑,特别是在Java这样的语言上,Java在虚拟机上运行,垃圾收集由Java运行时处理,因为这需要付出相当大的努力(我可以想象)从使用Java调用接口切换或执行本机库中的本机方法开始,因为必须有一种方法来分配堆栈上的空间,切换到本机代码,执行本机方法,切换回Java虚拟机,也许不知何故,堆栈上的空间没有被释放——这就是我将要做的倾向于思考

希望这有帮助, 顺致敬意,
Tom.

只是猜测:在JVM内部运行时,您可能正在使用一个非默认的
malloc
实现,该实现根据JVM的特定需求进行调整,并产生比普通libc实现中的通用
malloc
更多的开销。

Java需要为其堆提供连续内存,以便能够分配最大内存大小为虚拟内存。但是,这不会消耗物理内存,甚至可能不会消耗交换。我会检查驻留内存增加了多少。

很难说,但我认为问题的核心是,应用程序中有两个堆需要维护——标准Java堆Java对象分配(由JVM维护)和C堆(由调用malloc/free维护)。如果没有看到一些代码,很难说到底发生了什么。

这里有一个建议来解决这个问题

使C代码停止使用标准malloc调用,并使用malloc的替代版本,该版本通过
mmap
ing
/dev/zero
获取内存。您可以从库中修改malloc的实现,或者如果您有足够的能力这样做,也可以使用自己的实现


我强烈怀疑你会发现你的问题在你这么做之后就消失了。

对不起,伙计们。错误的假设

我已经习惯了Sun Java实现用于默认最大堆大小的64MB。但我使用openjdk 1.6进行测试。如果没有明确指定最大堆大小,openjdk将使用物理内存的一小部分。在我的例子中,四分之一。我使用的是4GB机器。因此四分之一是1GB。这就是C和Java之间的区别。

遗憾的是,这种行为在任何地方都没有记录。我在查看openjdk的源代码时发现了它(
arguments.cpp
):


有趣的观察。我没有预料到这种行为。malloc堆碎片。请参阅@LariHotari,而这个问题的原因是另一个(请参阅我的答案),我们确实也遇到了碎片问题。我们通过切换到其他实现,如tcmalloc、jemalloc或来自locklessinc的malloc实现,解决了这个问题。@EduardWirch感谢您提供了关于其他malloc实现的信息。您是否也用分配器重建了JVM(re:)或者只是将其用于库?是否存在任何问题?不需要重建或重新链接。只需确保先加载替代实现(LD_PRELOAD)JVM调用的库仍然可以释放分配的内存。一种可能性是,有一个Java线程与本机代码同时运行,它们正在分割内存。OP说有很多小的分配。Java的最大堆大小被设置为60MB左右。这不是多消耗1GB内存的原因y、 不过:驻留内存是3GB,就像c程序一样。包括所有共享库时,它可能会使用1GB的虚拟内存。虚拟内存的全部意义在于,您不必担心内存的使用方式,只有驻留内存实际消耗物理内存。为什么您关心它使用了多少地址空间,就像cari一样你的程序中的整数有多大。这也是我的猜测。但我不会给你+1,除非有证据证明确实如此。
// 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.