ult*_*ohn 9 c memory malloc free memory-management
我在某个地方读到free用来摆脱不是通过调用创建的对象是灾难性的,这是malloc真的吗?为什么?
sha*_*oth 15
这是未定义的行为 - 永远不要尝试.
让我们看看当你尝试free()自动变量时会发生什么.堆管理器必须推断如何获取内存块的所有权.要做到这一点,它要么必须使用一些单独的结构来列出所有已分配的块,而且这种结构非常慢,很少使用,或者希望必要的数据位于块的开头附近.
后者经常被使用,这就是我应该如何工作.当您调用malloc()时,堆管理器会分配稍大的块,在开头存储服务数据并返回偏移指针.Smth喜欢:
void* malloc( size_t size )
{
void* block = tryAlloc( size + sizeof( size_t) );
if( block == 0 ) {
return 0;
}
// the following is for illustration, more service data is usually written
*((size_t*)block) = size;
return (size_t*)block + 1;
}
Run Code Online (Sandbox Code Playgroud)
然后free()将尝试通过偏移传递的指针来访问该数据,但如果指针是自动变量,那么无论数据位于何处,它都希望找到服务数据.因此未定义的行为.很多时候服务数据被free()堆管理器修改以获取块的所有权 - 因此,如果指针传递给自动变量,则将修改和读取一些不相关的内存.
实施可能会有所不同,但您不应做出任何具体假设.仅调用free()由malloc()族函数返回的地址.
pet*_*hen 10
按照标准,它是"未定义的行为" - 即"任何事情都可能发生".但这通常是坏事.
在实践中:free'指针指的是修改堆.C运行时实际上永远不会验证传递的指针是否来自堆 - 这在任何时间或内存中都是昂贵的.结合这两个因素,你得到"免费(非malloced-ptr)将在某处写一些东西" - resutl可能是你背后修改的"你的"数据,访问违规,或破坏重要的运行时结构,如堆栈上的返回地址.
示例:灾难性场景:
您的堆实现为一个简单的空闲块列表.malloc意味着从列表中删除一个合适的块,free意味着再次将它添加到列表中.(典型的,如果简单的实现)
你释放()指向堆栈上的局部变量的指针.你是"幸运的",因为修改进入无关的堆栈空间.但是,部分堆栈现在位于您的免费列表中.
由于分配器设计和分配模式,malloc不太可能返回此块.后来,在程序的完全不相关的部分,你实际上得到这个块作为malloc的结果,写它象垃圾一样清除一些局部变量的堆栈,并返回一些重要的指针,当包含垃圾和你的应用程序崩溃.症状,复制和位置与实际原因完全无关.
调试那个.
有些人在这里指出这是"未定义的行为".我将进一步说,在某些实现中,这将导致程序崩溃或导致数据损坏.它与"malloc"和"free"的实现方式有关.
实现malloc/free的一种可能方法是在每个分配的区域之前放置一个小标头.在malloc'd区域,该标题将包含该区域的大小.释放该区域后,将检查该标头,并将该区域添加到相应的空闲列表中.如果发生这种情况,这是个坏消息.例如,如果释放在堆栈上分配的对象,则突然部分堆栈位于空闲列表中.然后malloc可能会返回该区域以响应将来的调用,并且您将在整个堆栈中乱写数据.另一种可能性是你释放一个字符串常量.如果该字符串常量位于只读内存中(通常是这样),则此假设实现将导致段错误并在稍后的malloc之后或者free将对象添加到其freelist时崩溃.
这是我正在谈论的假设实现,但你可以用你的想象力来看看它是如何变得非常非常错误的.某些实现非常强大,并且不容易受到这种精确类型的用户错误的影响.某些实现甚至允许您设置环境变量以诊断这些类型的错误.Valgrind和其他工具也会检测到这些错误.