我一直在一些项目上使用C获得硕士学位,但从未使用它构建生产软件.(.NET和Javascript是我的面包和黄油.)显然,需要free()记忆你malloc()在C中是至关重要的.如果你能在一个例行程序中做到这两件事,这很好,很好.但是随着程序的发展和结构的深入,跟踪什么是malloc"适合自由的地方和哪些内容"变得越来越难.
我查看了互联网,只找到了一些通用的建议.我怀疑的是,你们中的一些长期C编码员已经提出了自己的模式和实践来简化这个过程并将邪恶置于你面前.
那么:您如何建议构建C程序以防止动态分配成为内存泄漏?
按合同设计.确保每个函数注释都明确表示它的内存卫生 - 也就是说,它是否是mallocs,它的责任是释放分配的内容,以及它是否拥有传入的任何内容.并且与您的函数一致.
例如,您的头文件可能包含以下内容:
/* Sets up a new FooBar context with the given frobnication level.
* The new context will be allocated and stored in *rv;
* call destroy_foobar to clean it up.
* Returns 0 for success, or a negative errno value if something went wrong. */
int create_foobar(struct foobar** rv, int frobnication_level);
/* Tidies up and tears down a FooBar context. ctx will be zeroed and freed. */
void destroy_foobar(struct foobar* ctx);
Run Code Online (Sandbox Code Playgroud)
我衷心赞同使用Valgrind的建议,它是一个非常棒的工具,用于跟踪内存泄漏和无效的内存访问.如果您没有在Linux上运行,那么Electric Fence是一个类似的工具,虽然功能较少.
大型项目通常使用"池"技术:在此,每个分配都与池相关联,并在池时自动释放.如果您可以使用单个临时池进行一些复杂的处理,这非常方便,然后在您完成后可以一次性释放.子池通常是可能的; 你会经常看到一种模式:
void process_all_items(void *items, int num_items, pool *p)
{
pool *sp = allocate_subpool(p);
int i;
for (i = 0; i < num_items; i++)
{
// perform lots of work using sp
clear_pool(sp); /* Clear the subpool for each iteration */
}
}
Run Code Online (Sandbox Code Playgroud)
使用字符串操作可以使事情变得更容易.字符串函数将采用池参数,在该参数中,它们将分配其返回值,这也将是返回值.
缺点是: