【发布时间】:2012-04-11 15:43:22
【问题描述】:
我正在用 C 语言编写 min-heap 的实现,作为 Dijkstra 算法的一部分。我已经把所有细节都写下来了,我的测试程序通过了 valgrind 测试,但是它在这个过程中分配了荒谬的内存量。最后的测试是在INT_MAX by INT_MAX 的网格上(坐标只是整数),我在测试时得到SIGXCPU 错误。即使我只是将16k 位置插入队列然后删除所有内容,它仍然需要很长时间并分配超过8 MB。当我在巨大的网格测试用例上运行它时,它可以在我手动退出之前达到500 MB。会发生什么?这是我的代码的一部分:
struct position {
int x;
int y
};
typedef struct elt {
int priority;
int distance;
struct position p;
} *Elt;
typedef struct heap {
int size;
int capacity;
Elt *elts;
} *Heap;
void heap_insert(Heap h, Elt e, int *counter) {
if(h->capacity < (h->size + 2)) {
h->elts = realloc(h->elts, h->capacity * sizeof(Elt) * 2);
h->capacity *= 2;
}
h->elts[h->size] = malloc(sizeof(*Elt));
elt_assign(h->elts[h->size], e);
h->size++;
heapify(h->size, h->elts);
*counter = *counter + 1;
}
我所有的其他功能都一次性进行内存管理,在功能中进行,或者根本不进行。在这种情况下,初始大小是64,但我从1024 开始得到了相同的效果。我还尝试限制队列的大小,但无济于事。我很确定这不是我的堆积代码,但这只是以防万一
static void floatDown(int n, Elt *a, int pos) {
Elt x = malloc(sizeof(struct elt));
elt_assign(x, a[pos]);
for(;;) {
if(Child(pos, 1) < n && a[Child(pos, 1)]->priority < a[Child(pos, 0)]->priority) {
if(a[Child(pos, 1)]->priority < x->priority) {
elt_assign(a[pos], a[Child(pos, 1)]);
pos = Child(pos, 1);
} else {
break;
}
} else if(Child(pos, 0) < n && a[Child(pos, 0)]->priority < x->priority) {
elt_assign(a[pos], a[Child(pos, 0)]);
pos = Child(pos, 0);
} else {
break;
}
}
elt_assign(a[pos], x);
free(x);
}
static void heapify(int n, Elt *a) {
for(int i = n - 1; i >= 0; i--) {
floatDown(n, a, i);
}
}
任何帮助将不胜感激。
【问题讨论】:
-
我感觉
elt_assign方法在这里也会派上用场。 -
我同意 Makoto,至于您发布的代码没有明显的泄漏。
-
您说“它在进程中分配了荒谬的内存量”。它分配了多少?打印出 malloc 和 realloc 返回的值可能会有一些见解。 (我会制作包装函数 myMalloc 和 myRealloc)。 可能是内存在浮动开始时被 Elt
x = malloc...碎片化,所以我想知道 heap_insert 中的每个 realloc 是否都以某种低效的方式分配了一块全新的内存。还要对每个 malloc 和 realloc 计时,并打印时间,可能会显示指数减速。将Elt x = malloc替换为typedef struct elt e = a[pos]; -
我省略了 elt_assign 函数,因为我已经在问题中有大量代码,但它只是 e->p.x = temp->p.x 等。谢谢 gbulmer,我会尝试这两个。我相当有信心在 10≤x≤16 的情况下运行 2^x 次插入,我的速度会呈指数级下降。 16岁,速度慢得无法忍受。我并不是说每个 alloc 分配的内存比有意义的多,但是如果我将 8000 个 Elts 插入堆中,valgrind 将报告我分配了 8 MB 超过 50 万个分配(全部释放,但仍然太多) .另外,在您最后的建议中,为什么 typedef 应该在那里?
-
@jclancy - 抱歉,我复制错误+粘贴了;
typedef struct elt e = a[pos];应该是struct elt e = a[pos];。将 floatDown 中的Elt x = malloc...更改为struct elt e = a[pos];可能会显着减少 malloc'ed & free'd 的空间量;如果 floatdown 被调用 (N.log N) 次,那是相当多的 malloc+free 调用。
标签: c memory-management data-structures