当我用 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 bytes) 并且 gsl_vector 的block
指针被设置为刚刚分配的 gsl_block 的内存地址 - 3 个双精度数组是
malloc
'd,其内存地址分配给两个data
指针(一个 ingsl_block
和一个 ingsl_vector
)。
malloc
通过删除两个s ,我获得了 40% 的性能提升。我创建了我的自定义gsl_vector
创建例程,它分配了一个包含 3 个双精度数的数组,并将data
指针设置gsl_vector
为该数组的地址。然后我返回一个gsl_vector
(不是指针)。
但这样做,我仍然得到数百万次malloc(3 * sizeof(double))
操作。
我没有设法将 3 个双精度数组“嵌入”到gsl_vector
结构中,因为如果data
指针指向结构本身内部的东西(hacky!),那么当向量被复制到别处时指针不再有效!
你有什么想法(除了切换到 C++ 或滚动我自己的线性代数库)?我愿意接受任何建议。