以下是来自着名的LAPACK数值库的Fortran ZHEEVR例程的C包装器:
void zheevr(char jobz, char range, char uplo, int n, doublecomplex* a, int lda, double vl, double vu, int il, int iu, double abstol, double* w, doublecomplex* z, int ldz, int* info)
{
int m;
int lwork = -1;
int liwork = -1;
int lrwork = -1;
int* isuppz = alloc_memory(sizeof(int) * 2 * n);
zheevr_(&jobz, &range, &uplo, &n, a, &lda, &vl, &vu, &il, &iu, &abstol, &m, w, z, &ldz, isuppz, small_work_doublecomplex, &lwork, small_work_double, &lrwork, small_work_int, &liwork, &info);
lwork = (int) small_work_doublecomplex[0].real;
liwork = small_work_int[0];
lrwork = (int) small_work_double[0];
doublecomplex* work = alloc_memory(sizeof(doublecomplex) * lwork);
double* rwork = alloc_memory(sizeof(double) * lrwork);
int* iwork = alloc_memory(sizeof(int) * liwork);
zheevr_(&jobz, &range, &uplo, &n, a, &lda, &vl, &vu, &il, &iu, &abstol, &m, w, z, &ldz, isuppz, work, &lwork, rwork, &lrwork, iwork, &liwork, info);
free(iwork);
free(rwork);
free(work);
free(isuppz);
}
在我的应用程序中,这个函数被称为数十万次,以对复杂矩阵“a”(参数名称遵循此函数的Fortran约定)进行对角化,以获得相同的矩阵大小。我认为工作数组大小在大多数时候都是相同的,因为对角化矩阵将具有相同的结构。我的问题是:
答案 0 :(得分:5)
1)是的,他们可以。
2)任何理智的libc都不应该担心free()的顺序。表现明智也不重要。
我建议从此函数中删除内存管理 - 因此调用者将提供矩阵大小和分配的临时缓冲区。如果从相同大小的矩阵上的相同位置调用此函数,那将大大减少malloc的数量。
答案 1 :(得分:5)
如果两个答案都是“是”,请考虑使用VLA - 可变长度数组:
void zheevr(char jobz, char range, char uplo, int n, doublecomplex* a, int lda, double vl, double vu, int il, int iu, double abstol, double* w, doublecomplex* z, int ldz, int* info)
{
int m;
int lwork = -1;
int liwork = -1;
int lrwork = -1;
int isuppz[2*n];
zheevr_(&jobz, &range, &uplo, &n, a, &lda, &vl, &vu, &il, &iu, &abstol, &m, w, z, &ldz, isuppz, small_work_doublecomplex, &lwork, small_work_double, &lrwork, small_work_int, &liwork, &info);
lwork = (int) small_work_doublecomplex[0].real;
liwork = small_work_int[0];
lrwork = (int) small_work_double[0];
doublecomplex work[lwork];
double rwork[lrwork];
int iwork[liwork];
zheevr_(&jobz, &range, &uplo, &n, a, &lda, &vl, &vu, &il, &iu, &abstol, &m, w, z, &ldz, isuppz, work, &lwork, rwork, &lrwork, iwork, &liwork, info);
}
使用VLA的一个好处是,您无需自由完成。
(未经测试的代码!)
答案 2 :(得分:2)
这肯定会影响性能 - 你只能通过计时找到多少。要创建一个避免大多数分配的版本,请分配给静态指针并记住另一个静态整数的大小。如果下一个调用使用相同的大小,只需重用上次分配的内容即可。只有在需要创建新矩阵时才释放任何内容,因为大小已经改变。
请注意,此解决方案仅适用于单线程代码。
答案 3 :(得分:1)
好的。您很快就会得到探查器的答案。如果您有AMD机器,我强烈推荐免费的AMD CodeAnalyst。
至于你的记忆问题,我认为在这种情况下你可以使用本地内存管理。只需确定可为此功能分配的最大内存数。 接下来,您声明一个静态缓冲区,您可以使用它,就像编译器处理堆栈一样。我曾经在VirtualAlloc上做了一次这样的包装,而且非常快。
答案 4 :(得分:1)
如果要分配相同大小的项目数十万次,那么为什么不只是维护一堆对象(因为这些似乎相对简单,即不包含指向其他已分配内存的指针)并且自由进行你自己的堆(或实际堆栈)?
堆可以使用glib malloc懒惰地分配新对象,但是当释放时只需将项目推送到堆上。当你需要分配时,如果有一个可用的释放对象,它可以只分配那个。
这也将为您节省多次分配调用(因为您不需要进行任何分配,看起来您的例程会对malloc进行多次调用),并且至少在re上也会避免碎片(在某种程度上) - 使用的记忆。当然,初始分配(以及程序在需要扩展此内存时运行的其他分配)可能会导致碎片,但如果您真的担心这一点,您可以运行一些统计数据并找到您的平均/最大/典型大小运行期间堆,并在程序启动时立即预分配,避免碎片。