2009-10-31 92 views
5

以下是一个非常非常简单的版本malloc()似乎给我分配了一些空间,但除了没有free()的事实,我不检查我是否已超出分配的空间,我如何检查代码是否正确?内存分配在C

“C”专家会给我带来什么明显的失误?

#include <stdio.h> 
#include <unistd.h> 

#define MAX_MEMORY 1024 * 1024 * 2 /* 2MB of memory */ 

void *stack = NULL; /* pointer to available stack */ 
void * memoryAlloc(size) { 
    if (stack == NULL) 
     stack = sbrk(MAX_MEMORY); /* give us system memory */ 

    void *pointer; 
    pointer = (void *)stack + size; /* we always have space :) */ 
    stack += size; /* move in stack forward as space allocated */ 
    return pointer; 
} 
+0

我不会称之为内存“堆栈”的舞台。你当前的实现就像一个堆栈,是的,但是如果你打算像malloc一样工作,免费,那么它就是一堆。 – 2009-10-31 18:26:25

+0

非常感谢您的评论! – Radek 2009-10-31 18:29:00

+0

这个分配器是所谓的“池分配器”的开始 - 分配发生像上面那样,然后当使用池的工作单元完成时,整个块被立即释放回系统。它有助于处理由于必须单独管理每个小配置而导致的泄漏。 Apache使用池 - 一个HTTP请求进入,为请求设置一个池,当请求完成时池被释放。对请求没有任何其他工作需要担心释放动态分配的对象。 – 2009-10-31 19:08:09

回答

11

除了基本的问题Ned Batchelder指出,一个更微妙的问题是,一个allocator必须返回已正确的被分配任何对象对齐的地址。在某些平台(x86)上,除性能问题外,这可能并不重要,但在许多平台上,这是一个完整的交易断路器。

我还必须执行(char*)强制执行stack指针算术(您不能对void*类型执行指针算术)。

而且你应该在MAX_MEMORY宏的表达式中放置parens。如果没有它们,我不认为你会遇到任何优先级问题,因为所有高优先级运算符都不是乘法运算,因此无论如何都不是正确的语法。与宏,它是总是比对不起更安全。 (至少有一个例外,其中[]运算符只能绑定到2而不是整个MAX_MEMORY表达式,但即使它在语法上有效,看到MAX_MEMORY[arrayname]也是一种非常奇怪的情况。

事实上,我会把它作为一个枚举。

你或许可以保持分配器简单通过返回的内存块已正确任何基本数据类型对齐系统(也许一个8字节对齐)上:

/* Note: the following is untested     */ 
/*  it includes changes suggested by Batchelder */ 

#include <stdio.h> 
#include <unistd.h> 

enum { 
    kMaxMemory = 1024 * 1024 * 2, /* 2MB of memory */ 
    kAlignment = 8 
}; 

void *stack = NULL; /* pointer to available stack */ 
void * memoryAlloc(size_t size) { 
    void *pointer; 

    size = (size + kAlignment - 1) & ~(kAlignment - 1); /* round size up so allocations stay aligned */ 

    if (stack == NULL) 
    stack = sbrk(kMaxMemory); /* give us system memory */ 

    pointer = stack; /* we always have space :) */ 
    stack = (char*) stack + size; /* move in stack forward as space allocated */ 
    return pointer; 
} 
+0

测试和工作 – Radek 2009-10-31 19:33:00

6

有几个问题:

  1. 您在函数中,这是不是在C.

  2. 您可以设置指针stack+size允许申报pointer,但你想它只是stack。否则,您将返回一个指向您分配的内存块结尾的指针。因此,如果您的调用者在该指针处使用了全部size字节,他将与另一个内存块重叠。如果在不同的时间获得不同大小的块,则会有两个调用者尝试使用相同的内存字节。

  3. 当你做stack += size,你是不是size字节,但通过size无效*的,几乎总是大递增stack

+3

从C99开始,函数中间的声明已被允许。 – 2009-10-31 18:23:18

+0

oops:我正在展示我的年龄! – 2009-10-31 18:24:43

+0

所有优点,+1 – 2009-10-31 18:26:41

2

第一,其他都已经注意到,你在块的中间声明变量,只允许在C99中使用,但不能在C89/90中使用。即我们必须得出结论,您正在使用C99。其次,你正在用K & R-style(无参数类型)定义你的函数,但同时不在以后声明参数类型。这样你就可以依靠C99中不合法的“隐式int”规则。即我们必须得出结论,你使用C99的是而不是。这已经是与“第一”部分的矛盾。 (此外,通常使用无符号的类型来表示“对象大小”的概念。size_t是通常用于此目的的专用类型)。

第三,您在指针上使用指针运算,这在C89/90和C99中都是非法的。我甚至不知道我们可以从中得出什么结论:)

请确定您尝试使用哪种语言,我们将从那里开始。

+0

我错过了'size'的隐式声明。 – 2009-10-31 18:37:18

+0

谢谢AndreyT,我打算使用C89,你可以得出结论,我是一个新手,但有很多有用的输入:)。 – Radek 2009-10-31 21:02:38