简体   繁体   English

静态指针动态分配缓冲区内的函数

[英]Static pointer to dynamically allocated buffer inside function

I have a function in C that dynamically allocates a buffer, which is passed to another function to store its return value. 我在C中有一个动态分配缓冲区的函数,它被传递给另一个函数来存储它的返回值。 Something like the following dummy example: 像下面的虚拟示例:

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 is called by an iterator over a multi-dimensional array (it's a NumPy gufunc kernel, to be precise), so it gets called millions of times with the same value for data_len . function由迭代器在多维数组上调用(确切地说,它是一个NumPy gufunc内核),因此对于data_len ,它被调用数百万次。 It seems wasteful to be creating and destroying the buffer over and over again. 一遍又一遍地创建和销毁缓冲区似乎很浪费。 I would normally move allocation of the buffer to the function that calls function , and pass a poiinter to it, but I don't directly control that, so not possible. 我通常会将缓冲区的分配移动到调用function ,并将poiinter传递给它,但我不直接控制它,所以不可能。 Instead, I am considering doing the following: 相反,我正在考虑做以下事情:

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 */
    }
}

That means that I never directly free the memory I allocate: it gets reused in subsequent calls, and then lingers there until my program exits. 这意味着我永远不会直接释放我分配的内存:它会在后续调用中重用,然后在那里徘徊直到我的程序退出。 It doesn't seem like the right thing to do, but not too bad either, as the amount of memory allocated is always going to be small. 这似乎不是正确的事情,但也不是太糟糕,因为分配的内存量总是很小。 Am I over worrying? 我过度担心吗? Is there a better approach to this? 有更好的方法吗?

This approach is legitimate (but see below), although tools like valgrind will incorrectly flag it as a "leak". 这种方法是合法的(但见下文),尽管像valgrind这样的工具会错误地将其标记为“泄漏”。 (It's not a leak, as a leak is an unbounded increase in memory usage.) You might want to benchmark exactly how much time is lost on malloc and free compared to other things the function is doing. (这不是泄漏,因为泄漏是内存使用量的无限增加。)您可能希望准确地确定mallocfree与其他功能相比所耗费的时间。

If you can use C99 or gcc, and if your buffer is not overly large, you should also consider variable-length arrays, which are as fast (or faster than) a static buffer, and create no fragmentation. 如果你可以使用C99或gcc,并且你的缓冲区不是太大,你还应该考虑变长数组,它与静态缓冲区一样快(或快),并且不会产生碎片。 If you're on another compiler, you can look into the non-standard (but widely supported ) alloca extension. 如果您使用的是另一个编译器,则可以查看非标准(但广泛 支持的 )alloca扩展。

You do need to be aware that using a static buffer makes your function: 您需要注意使用静态缓冲区使您的功能:

  1. Thread-unsafe - if it is called from multiple threads simultaneously, it will destroy the data of the other instance. 线程不安全 - 如果同时从多个线程调用它,它将破坏另一个实例的数据。 If the Python is called from numpy, this is probably not a problem, as threads will be effectively serialized by the GIL. 如果从numpy调用Python,这可能不是问题,因为GIL会有效地序列化线程。

  2. Non-reentrant - if other_function calls some Python code which ends up calling function - for whatever reason - before function finishes, your function will again destroy its own data. 非重入 - 如果other_function调用一些最终调用function Python代码 - 无论出于何种原因 - 在function完成之前,你的函数将再次销毁自己的数据。

If you don't need true parallel execution and reentrancy, this use of static variables is fine, and a lot of C code uses them that way. 如果你不需要真正的并行执行和重入,那么static变量的使用就可以了,许多C代码都是这样使用它们的。

This is a fine approach, and something like this is likely used internally by many libraries. 这是一种很好的方法,许多库可能会在内部使用这种方法。 The memory will be freed automatically when the program exits. 程序退出时,内存将自动释放。

You might want to round buf_len up to a multiple of some block size, so you don't realloc() every time data_len changes a small bit. 您可能希望将buf_len舍入到某个块大小的倍数,因此每次data_len稍微改变时都不会重新realloc() But if data_len is almost always the same size, this isn't necessary. 但是如果data_len几乎总是相同的大小,那么这不是必需的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM