代码之家  ›  专栏  ›  技术社区  ›  Eduard Wirch

为什么当使用Linux时,一个原生库使用1.5倍的内存?

  •  7
  • Eduard Wirch  · 技术社区  · 16 年前

    我用C语言编写了一个库,它消耗大量内存(数百万个小块)。我写了一个使用这个库的C程序。我编写了一个Java程序,它使用同一个库。Java程序是图书馆周围非常薄的一层。基本上只有一个本地方法被调用,完成所有的工作并在数小时后返回。Java和本地调用库之间没有使用Java调用接口的进一步通信。也没有Java对象消耗了大量值得注意的内存。

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

    我检查了Java进程的内存映射(使用PMAP)。图书馆只使用40MB。因此,由Java加载的附加库不是原因。

    有人能解释这种行为吗?

    编辑 :谢谢你的回答。使它更清楚一点:Java代码除了调用本地库之外什么也不做。 一次 !Java堆是标准大小(也许60MB),不使用(除了包含主方法的一个类和调用本地库的另一个类)。

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

    6 回复  |  直到 16 年前
        1
  •  3
  •   Joachim Sauer    16 年前

    只是猜测:您可能正在使用非默认值 malloc 在JVM中运行时的实现,它可以调到JVM的特定需求,并产生比一般用途更多的开销 马洛克 在您的常规libc实现中。

        2
  •  2
  •   Eduard Wirch    16 年前

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

    我已经习惯了用以实现默认最大堆大小的Sun Java实现的64 MB。但我用OpenJDK1.6进行测试。如果没有显式指定最大堆大小,则openjdk使用物理内存的一部分。在我的例子中是四分之一。我用的是4GB的机器。因此,四分之一是1 GB。这就是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.
    
        3
  •  1
  •   Peter Lawrey    16 年前

    Java需要为其堆拥有连续内存,因此它可以将最大内存大小分配为虚拟内存。但是,这不会消耗物理内存,甚至可能不会消耗交换。我会检查你的常驻记忆增加了多少。

        4
  •  0
  •   t0mm13b    16 年前

    有很多因素需要考虑,尤其是在Java这样的语言上,Java运行在虚拟机上,垃圾收集是由Java运行时来处理的,因为有相当大的努力(我想)使用Java调用接口来在本地库中切换或执行本地方法。必须是一种在堆栈上分配空间、切换到本机代码、执行本机方法、切换回Java虚拟机的方法,或者不知何故,堆栈上的空间没有被释放——这就是我倾向于思考的。

    希望这有帮助, 最好的问候, 汤姆。

        5
  •  0
  •   Joe M    16 年前

    很难说,但我认为问题的核心是在应用程序中需要维护两个堆——Java对象分配的标准Java堆(由JVM维护),以及通过调用MALOC/FULL维护的C堆。在没有看到一些代码的情况下,很难说到底发生了什么。

        6
  •  0
  •   Omnifarious    16 年前

    这里有一个反对它的建议。

    使用标准malloc调用停止C代码,并使用另一个版本的malloc来获取内存 mmap 惯性导航与制导 /dev/zero . 您可以从一个库中修改malloc的实现,或者如果您觉得有足够的能力这样做的话,可以自己滚动。

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