我在C中有一个动态分配缓冲区的函数,该缓冲区被传递给另一个函数来存储它的返回值。类似于以下虚拟示例:
void other_function(float in, float *out, int out_len) {
/* Fills 'out' with 'out_len' values calculated from 'in' */
}
void function(float *data, int data_len, float *out) {
float *buf;
int buf_len = 2 * data_len, i;
buf = malloc(sizeof(float) * buf_len);
for (i = 0; i < data_len; i++, data++, out++) {
other_function(*data, buf, buf_len);
/* Do some other stuff with the contents of buf and write to *out */
}
free buf;
}
迭代器通过多维数组调用 function
(确切地说,它是一个NumPy gufunc内核),因此它被data_len
的相同值调用数百万次。一遍又一遍地创建和销毁缓冲区似乎很浪费。我通常会将缓冲区的分配移动到调用function
的函数,并将poiinter传递给它,但我不直接控制它,所以不可能。相反,我正在考虑做以下事情:
void function(float *data, int data_len, float *out) {
static float *buf = NULL;
static int buf_len = 0;
int i;
if (buf_len != 2 * data_len) {
buf_len = 2 * data_len;
buf = realloc(buf, sizeof(float) * buf_len); /* same as malloc if buf == NULL */
}
for (i = 0; i < data_len; i++, data++, out++) {
other_function(*data, buf, buf_len);
/* Do some other stuff with the contents of buf and write to *out */
}
}
这意味着我永远不会直接释放我分配的内存:它会在后续调用中重用,然后一直存在,直到我的程序退出。这似乎不是正确的事情,但也不是太糟糕,因为分配的内存量总是很小。我过度担心吗?有更好的方法吗?
答案 0 :(得分:5)
这种方法是合法的(但见下文),尽管像valgrind这样的工具会错误地将其标记为“泄漏”。 (这不是泄漏,因为泄漏是无限内存使用量的增加。)您可能希望准确地计算malloc
和free
与...相比的丢失时间功能正在做的其他事情。
如果您可以使用C99或gcc,并且缓冲区不是太大,您还应该考虑可变长度数组,它与静态缓冲区一样快(或快),并且不会产生碎片。如果您使用的是其他编译器,则可以查看非标准(但widely supported)alloca扩展名。
您需要注意使用静态缓冲区可以实现您的功能:
Thread-unsafe - 如果同时从多个线程调用它,它将破坏另一个实例的数据。如果从numpy调用Python,这可能不是问题,因为GIL会有效地序列化线程。
不可重入 - 如果other_function
调用某些Python代码,最终调用function
- 无论出于何种原因 - 在function
完成之前,您的函数将再次销毁自己的数据
如果你不需要真正的并行执行和重入,那么static
变量的使用就可以了,许多C代码都是这样使用的。
答案 1 :(得分:2)
这是一种很好的方法,许多库内部都可能使用这种方法。程序退出时,内存将自动释放。
您可能希望将buf_len
舍入到某个块大小的倍数,因此每次realloc()
更改一小部分时都不会data_len
。但如果data_len
几乎总是相同的大小,那么这不是必需的。