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

时间:2016-08-28 18:54:29

标签: c++ c

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

2 个答案:

答案 0 :(得分:4)

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

主要是两个

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

(2)或者,重新编码您的函数以使用模拟“堆栈”的“堆栈框架”结构。实际的功能不再是递归的。无论堆允许什么,这几乎都是无限的

对于(1)......

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

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

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

使用(A),假设堆栈扩展系统调用许可,限制可以是堆栈允许的所有可用内存[达到某个系统范围或RLIMIT_ *参数]。

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

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

对于(2)......

这可以根据需要逐字扩展/收缩。其中一个优点是您不需要事先猜测您需要多少内存。 [pseudo]堆栈可以根据需要继续增长[直到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 memory\n");
            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;
}

答案 1 :(得分:0)

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