在使用内存方面,用户定义的堆栈和内置的堆栈有什么区别?

What is the difference between user defined stack and built in stack in use of memory?

本文关键字:堆栈 内置 什么 区别 定义 内存 方面 用户      更新时间:2023-10-16

我想使用用户定义的堆栈为我的程序有大量的递归调用?定义用户定义的堆栈有用吗?

有几种方法可以做到这一点。

主要

两个:

(1)使用CPU/处理器堆栈。有一些变体,每个都有自己的局限性。

(2)或者,重新编码你的函数,使用一个模拟"堆栈"的"堆栈帧"结构体。实际的函数不再是递归的。这实际上可以是无限的,直到堆允许


For(1)…

(A)如果您的系统允许,您可以发出syscall来扩展进程的堆栈大小。这可能会限制您执行此操作的数量,并与共享库地址发生冲突。

(B)你可以malloc一个大的区域。使用一些[有点]复杂的内联asm技巧,您可以将该区域交换为堆栈[并再次返回],并将此malloc区域作为堆栈调用函数。可行,但不适合胆小的人……

(C)更简单的方法是大面积malloc。将该区域传递给pthread_attr_setstack。然后,使用pthread_create将递归函数作为线程运行。注意,你并不真正关心多线程,它只是一种简单的方法来避免asm的"混乱"把戏。

对于(A), 假设堆栈扩展系统调用允许,限制可能是堆栈允许的所有可用内存[不超过某个系统范围或RLIMIT_*参数]。

对于(B)和(C),您必须在开始之前"猜测"并使malloc足够大。完成后,大小是固定的,并且可以进一步扩展而不是

事实上,这并不完全正确。重复使用asm技巧[当需要时],你可以模拟一个接近无限的堆栈。但是,在我看来,跟踪这些大型malloc区域的开销足够高,我选择下面的(2)。


For(2)…

可以根据需要扩展/收缩。其中一个优点是,您不需要事先猜测需要多少内存。[伪]堆栈可以根据需要继续增长[直到malloc返回NULL:-)]。

下面是一个递归函数示例[将其视为伪代码]:

int
myfunc(int a,int b,int c,int d)
{
    int ret;
    // do some stuff ...
    if (must_recurse)
        ret = myfunc(a + 5,b + 7,c - 6,d + 8);
    else
        ret = 0;
    return ret;
}

这个函数被改成使用struct作为栈帧[再次,松散的伪代码]:

typedef struct stack_frame frame_t;
struct stack_frame {
    frame_t *prev;
    int a;
    int b;
    int c;
    int d;
};
stack_t *free_pool;
#define GROWCOUNT   1000
frame_t *
frame_push(frame_t *prev)
{
    frame_t *cur;
    // NOTE: we can maintain a free pool ...
    while (1) {
        cur = free_pool;
        if (cur != NULL) {
            free_pool = cur->prev;
            break;
        }
        // refill free pool from heap ...
        free_pool = calloc(GROWCOUNT,sizeof(stack_t));
        if (free_pool == NULL) {
            printf("frame_push: no memoryn");
            exit(1);
        }
        cur = free_pool;
        for (int count = GROWCOUNT;  count > 0;  --count, ++cur)
            cur->prev = cur + 1;
        cur->prev = NULL;
    }
    if (prev != NULL) {
        *cur = *prev;
        cur->prev = prev;
        cur->a += 5;
        cur->b += 7;
        cur->c += 6;
        cur->d += 8;
    }
    else
        memset(cur,0,sizeof(frame_t));
    return cur;
}
frame_t *
frame_pop(frame_t *cur)
{
    frame_t *prev;
    prev = cur->prev;
    cur->prev = free_pool;
    free_pool = cur;
    return prev;
}
int
myfunc(void)
{
    int ret;
    stack_t *cur;
    cur = frame_push(NULL);
    // set initial conditions in cur...
    while (1) {
        // do stuff ...
        if (must_recurse) {
            cur = frame_push(cur);
            must_recurse = 0;
            continue;
        }
        // pop stack
        cur = frame_pop(cur);
        if (cur == NULL)
            break;
    }
    return ret;
}

所有的函数、对象、变量和用户定义结构都使用由操作系统和编译器控制的内存空间。所以,这意味着你定义的堆栈在一个通用的内存空间下工作,这个内存空间是为你的进程的堆栈在OS中指定的。因此,它没有太大的区别,但是您可以定义一个高效的优化结构来更好地使用这个通用堆栈。