malloc 内存分配的替代方案作为堆栈

malloc alternative for memory allocation as a stack

我正在寻找 mallocc 替代方案,它只会用作堆栈。更像是 alloca 但不受堆栈大小限制 space 。它用于编写数学算法。

我的问题是,是否有类似的东西,或者这是否易于实施?

我在旧的 FORTRAN 程序中看到了一种策略,它可能正是您正在寻找的。该策略涉及使用从 main.

向下传递到每个函数的全局数组
char global_buffer[SOME_LARGE_SIZE];

void foo1(char* buffer, ...);
void foo2(char* buffer, ...);
void foo3(char* buffer, ...);

int main()
{
   foo1(global_buffer, ....);
}

void foo1(char* buffer, ...)
{
   // This function needs to use SIZE1 characters of buffer.
   // It can let the functions that it calls use buffer+SIZE1

   foo2(buffer+SIZE1, ...);

   // When foo2 returns, everything from buffer+SIZE1 is assumed
   // to be free for re-use.
}

void foo2(char* buffer, ...)
{
   // This function needs to use SIZE2 characters of buffer.
   // It can let the functions that it calls use buffer+SIZE2

   foo3(buffer+SIZE2, ...);
}

void foo3(char* buffer, ...)
{
   // This function needs to use SIZE3 characters of buffer.
   // It can let the functions that it calls use buffer+SIZE3

   bar1(buffer+SIZE3, ...);
}

正如您已经发现的那样,只要它与 malloc 一起工作,您就应该使用它,并且只有在需要发挥最后一点性能时才回来。

一个适合这种情况的想法:您可以使用一个块列表,在需要时分配。使用列表可以在您达到虚拟内存限制时最终换出数据。

struct block {
  size_t size;
  void * memory;
  struct block * next;
};
struct stacklike {
  struct block * top;
  void * last_alloc;
};
void * allocate (struct stacklike * a, size_t s) {
  // add null check for top
  if (a->top->size - (a->next_alloc - a->top->memory) < s + sizeof(size_t)) {
    // not enough memory left in top block, allocate new one
    struct block * nb = malloc(sizeof(*nb));
    nb->next = a->top;
    a->top = nb;
    nb->memory = malloc(/* some size large enough to hold multiple data entities */);
    // also set nb size to that size
    a->next_alloc = nb->memory;
  }
  void * place = a->next_alloc;
  a->next_alloc += s;
  *((size_t *) a->next_alloc) = s; // store size to be able to free
  a->next_alloc += sizeof (size_t);
  return place;
}

我希望这能说明总体思路,对于实际实施,还有很多需要考虑的地方。

要换出内容,请将其更改为双向链表并跟踪分配的总字节数。如果达到限制,请将结尾写入某个文件。

这听起来像是 Obstack 的完美用法。

我自己从来没有用过它,因为 API 真的很混乱,我现在找不到例子。但是它支持你想要的所有操作,另外还支持流式创建"current"对象。

编辑:举了一个简单的例子。 Obstack API 显示出岁月痕迹,但 原则 至少是合理的。

您可能需要研究调整 align/block 设置,如果您喜欢种植,可能会使用 obstack_next_freeobstack_object_size

#include <obstack.h>
#include <stdio.h>
#include <stdlib.h>

void *xmalloc(size_t size)
{
    void *rv = malloc(size);
    if (rv == NULL)
        abort();
    return rv;
}

#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free

const char *cat(struct obstack *obstack_ptr, const char *dir, const char *file)
{
    obstack_grow(obstack_ptr, dir, strlen(dir));
    obstack_1grow(obstack_ptr, '/');
    obstack_grow0(obstack_ptr, file, strlen(file));
    return obstack_finish(obstack_ptr);
}

int main()
{
    struct obstack main_stack;
    obstack_init(&main_stack);
    const char *cat1 = cat(&main_stack, "dir1", "file1");
    const char *cat2 = cat(&main_stack, "dir1", "file2");
    const char *cat3 = cat(&main_stack, "dir2", "file3");
    puts(cat1);
    puts(cat2);
    puts(cat3);
    obstack_free(&main_stack, cat2);
    // cat2 and cat3 both freed, cat1 still valid
}