我想知道malloc和free是怎么工作的。
int main() {
unsigned char *p = (unsigned char*)malloc(4*sizeof(unsigned char));
memset(p,0,4);
strcpy((char*)p,"abcdabcd"); // **deliberately storing 8bytes**
cout << p;
free(p); // Obvious Crash, but I need how it works and why crash.
cout << p;
return 0;
}
如果答案是在记忆层面上的深度,如果可能的话,我会非常感激。
你的程序崩溃是因为它使用了不属于你的内存。它可能被其他人使用,也可能没有——如果你幸运的话,你崩溃了,如果没有,问题可能会隐藏很长一段时间,然后回来咬你一口。
就malloc/free实现而言——整本书都致力于这个主题。基本上,分配器会从操作系统中获得更大的内存块,并为你管理它们。分配器必须解决的一些问题是:
How to get new memory
How to store it - ( list or other structure, multiple lists for memory chunks of different size, and so on )
What to do if the user requests more memory than currently available ( request more memory from OS, join some of the existing blocks, how to join them exactly, ... )
What to do when the user frees memory
Debug allocators may give you bigger chunk that you requested and fill it some byte pattern, when you free the memory the allocator can check if wrote outside of the block ( which is probably happening in your case)
...
理论上,malloc为这个应用程序从操作系统获取内存。然而,由于您可能只需要4个字节,而操作系统需要在页面上工作(通常是4k), malloc所做的要比这多一点。它取一个页面,并把它自己的信息放在那里,这样它就可以跟踪你从该页中分配和释放了什么。
例如,当分配4个字节时,malloc会提供一个指向4个字节的指针。您可能没有意识到的是,在4个字节之前的8-12个字节的内存被malloc用来构成您已分配的所有内存的链。当你调用free时,它会取你的指针,备份到它的数据所在的位置,并对其进行操作。
当你释放内存时,malloc将内存块从链上取下…并且可能会也可能不会将这些内存返回给操作系统。如果它这样做,那么访问内存可能会失败,因为操作系统将拿走你访问该位置的权限。如果malloc保留内存(因为它在该页中分配了其他内容,或者用于某些优化),则访问将正常工作。这仍然是错误的,但可能会起作用。
免责声明:我所描述的是malloc的一种常见实现,但绝不是唯一可能的实现。
您的strcpy行尝试存储9个字节,而不是8个字节,因为有NUL结束符。它调用未定义的行为。
The call to free may or may not crash. The memory "after" the 4 bytes of your allocation might be used for something else by your C or C++ implementation. If it is used for something else, then scribbling all over it will cause that "something else" to go wrong, but if it isn't used for anything else, then you could happen to get away with it. "Getting away with it" might sound good, but is actually bad, since it means your code will appear to run OK, but on a future run you might not get away with it.
使用调试风格的内存分配器,您可能会发现在那里写了一个特殊的保护值,free会检查该值,如果没有找到它就会惊慌失措。
否则,您可能会发现接下来的5个字节包括属于某个尚未分配的其他内存块的链接节点的一部分。释放块很可能涉及将其添加到可用块的列表中,并且由于您在列表节点中乱写了代码,该操作可能会解除对具有无效值的指针的引用,从而导致崩溃。
这完全取决于内存分配器——不同的实现使用不同的机制。