2011-08-22 31 views
2

我有一个本地的C库,它可以在非常大的数据集上运行一些算法(从数百MB到数千Gb)。这是使用JNA在Java框架内调用的。 Java加载数据并通过JNA将它传递给C库。巨大的内存占用量使得使用JNA从Java本地C调用

问题是,似乎使用了过多的内存。对于一个数据集,在Java端完成所有加载并且C库使用2.0gb(使用内部内存管理确定)后,进程使用约3.0gb。但是一旦C库被调用,这个过程最终会达到9.5GB!

具体问题,然后:

Java和C端没有重叠吗?也就是说,JNA是否生成Java数据的C有效副本(顺便说一下,所有int和double数组),并将其传递给本地库,而不是包含Java中数据的相同块?

即使假设没有重叠,并且本机库正在使用JVM中包含的数据的副本,那么额外的4.5GB来自哪里呢?这大约是进程占用的系统内存量的两倍,我无法想象它会发生什么。关于JNA的这些方面的文档似乎非常有限,但我想知道是否有人比我更熟悉JNA,可能知道为什么它会使用如此之多的内存,以及如何以及如何能够减少其占用空间。

编辑:启用JNA-Java类看起来是这样的:

public interface MyNativeLibrary extends Library { 

    MyNativeLibrary INSTANCE = (MyNativeLibrary) Native.loadLibrary(
      "native_library", MyNativeLibrary.class); 

    int native_library_function(int num_inputs, int inputs[], int max_num_outputs, int preallocated_outputs[]); 

} 

在这种情况下,本地函数的返回值将是产出数量返回,或错误代码。 C接口用int32_t指定,以确保大小匹配。

+1

听起来像是你库中的一个bug,或者有你不知道的内存分配,或者你的JNA胶水中有bug。 –

+0

你是如何编写JNA绑定的?没有看到任何代码很难说... – bdonlan

回答

1

如果您只想在本机端分配内存,请在JNA中使用Memory类,并使用java.nio.ByteBuffer(内存有一个getByteBuffer()方法)访问内存。您可以将您的整数数组作为JNA指向分配的内存。这应该为您节省相当多的空间并提高性能。只要确保你在Java端管理本地内存资源。

+0

这实际上是我做的。因为我认为使用JNA(我们拥有数千万条记录)会造成限制性开销,所以我一直犹豫要在本机端分配这些东西,并在读取数据集时将其进行构建。 但是,使用JNA指针类,我分配了本机“对象”,然后在读取它们时传入记录中。它没有花费更多的时间,并且将内存使用降低到大约7.5g。这仍然看起来很糟糕,但它有25%的提高,所以我会接受。 – david