当我用C ++编写线性代数程序时,我使用的是Armadillo库。它基于模板,它为我提供了一种定义任何长度的向量的方法,这些向量不一定需要额外的内存分配,因为它们在编译时被静态分配了适当的内存缓冲区。当我使用arma::Col<double>::fixed<3>
时,编译器会动态创建一个“新类型”,以便向量包含一个恰好3个双精度的缓冲区。
现在我正在研究C中的线性代数程序,我正在使用GNU科学库(GSL)。为了实例化3D矢量,我执行:gsl_vector_alloc(3)
,返回gsl_vector*
。问题是这个操作会导致一小部分内存的动态分配,这在程序运行时会发生数百万次。我的程序浪费了大量资源来执行数千万malloc
/ free
次操作。
我检查过gsl_vector
的内部结构:
typedef struct
{
size_t size;
size_t stride;
double * data;
gsl_block * block;
int owner;
} gsl_vector;
为使库正常工作,data
应指向向量的第一个元素,通常位于gsl_block
结构中,如下所示:
typedef struct
{
size_t size;
double * data;
} gsl_block;
包含另一个data
指针。因此,为了实例化一个简单的3D向量,malloc
s的这个序列发生了:
gsl_vector
结构为malloc
'd(x86_64上大约40个字节)。gsl_block
结构为malloc
'd(16字节),gsl_vector的block
指针设置为刚刚分配的gsl_block的内存地址malloc
'd,其内存地址分配给data
个指针(gsl_block
中的一个和gsl_vector
中的一个)。 通过删除两个malloc
,我获得了40%的性能提升。我创建了自定义gsl_vector
创建例程,它分配了一个3个双精度数组,并将data
的{{1}}指针设置为该数组的地址。然后我返回gsl_vector
(不是指针)
但这样做,我仍然可以获得数百万次gsl_vector
次操作。
我没有设法在malloc(3 * sizeof(double))
结构中“嵌入”3个双精度数组,因为如果gsl_vector
指针指向 in 结构中的某些内容本身(hacky!),当向量被复制到别处时,指针不再有效!
你有什么想法(除了转换到C ++或滚动我自己的线性代数库)?我对任何建议持开放态度。
答案 0 :(得分:4)
我认为你好像误解了gls_block
数据结构的目的。在我看来,您应该只使用它在gsl_block
数据结构中分配大块数据,然后将该块拆分以供多个gsl_vector
使用。如果您通过分配一组数组来一次性分配所有gsl_vector
,那么您几乎就在那里。您只需要两次调用malloc
,并在初始化期间进行一些簿记。
这对你造成的影响是,你必须事先准确地考虑你需要的gsl_vector
。但是,当您使用没有内置垃圾收集的语言时,这就是支付的“价格”。如果您投资于此,大多数时候它都具有构建代码的优势,您可能会学到如何组织计算。
答案 1 :(得分:0)
C有点过于原始,不能正确地做到这一点。
如果您需要使用GSL中的函数,您可能仍然可以使用C ++ Armadillo向量和矩阵。
例如,您可以通过.memptr()成员函数获取指向矢量或矩阵使用的内存的指针。这也适用于固定大小的矩阵/向量。
或者,您可以告诉Armadillo使用已经分配的内存块,方法是在向量或矩阵construction期间给它一个指针。