如果一个编译器打包了自己独立版本的malloc/calloc/free/realloc,且作者认为这样做值得付出的努力,那么它可以合理地执行所示的优化。即使是链接到外部提供的函数的编译器,如果记录了它不把这些函数的调用顺序视为可观察的副作用,仍然可以执行这样的优化,但这种处理可能会更脆弱一些。
如果在malloc()和realloc()之间没有分配或释放存储空间,当执行malloc()时就已经知道realloc()的大小,并且realloc()的大小大于malloc()的大小,则将malloc()和realloc()操作合并成单个更大的分配可能是有意义的。但是,如果内存状态在此期间发生改变,这种优化可能会导致本应成功的操作失败。例如,给定以下序列:
void *p1 = malloc(2000000000);
void *p2 = malloc(2);
free(p1);
p2 = realloc(p2, 2000000000);
在p1被释放之后,系统可能才有2000000000个字节可用于p2。如果更改代码如下:
void *p1 = malloc(2000000000);
void *p2 = malloc(2000000000);
free(p1);
这将导致分配p2的失败。因为标准从未保证分配请求会成功,所以这种行为不算不符合标准。另一方面,以下也是“符合标准”的实现:
void *malloc(size_t size) { return 0; }
void *calloc(size_t size, size_t count) { return 0; }
void free(void *p) { }
void *realloc(void *p, size_t size) { return 0; }
这样的实现或许可以被认为比大多数其他实现更加“高效”,但除了在罕见情况下上述函数被调用但从未执行的代码路径中,很难将其视为非常有用。
我认为标准显然允许优化,至少在像原始问题中那样简单的情况下是可以的。即使在可能导致操作失败的情况下,标准仍然允许这种优化。很可能,许多编译器没有执行此优化的原因是作者认为收益不足以证明确定案例安全且有效所需的努力。
malloc
函数的库,该怎么办? - Gerhardh