我想知道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) ...

其他回答

正如aluser在这个论坛上说的:

Your process has a region of memory, from address x to address y, called the heap. All your malloc'd data lives in this area. malloc() keeps some data structure, let's say a list, of all the free chunks of space in the heap. When you call malloc, it looks through the list for a chunk that's big enough for you, returns a pointer to it, and records the fact that it's not free any more as well as how big it is. When you call free() with the same pointer, free() looks up how big that chunk is and adds it back into the list of free chunks(). If you call malloc() and it can't find any large enough chunk in the heap, it uses the brk() syscall to grow the heap, i.e. increase address y and cause all the addresses between the old y and the new y to be valid memory. brk() must be a syscall; there is no way to do the same thing entirely from userspace.

Malloc()依赖于系统/编译器,所以很难给出一个具体的答案。基本上,它会跟踪它所分配的内存,这取决于它是如何做的,所以你对free的调用可能失败或成功。

malloc()和free()并不是在每个O/S上都以相同的方式工作。

How malloc() and free() works depends on the runtime library used. Generally, malloc() allocates a heap (a block of memory) from the operating system. Each request to malloc() then allocates a small chunk of this memory be returning a pointer to the caller. The memory allocation routines will have to store some extra information about the block of memory allocated to be able to keep track of used and free memory on the heap. This information is often stored in a few bytes just before the pointer returned by malloc() and it can be a linked list of memory blocks.

通过写入超过malloc()分配的内存块,您很可能会破坏下一个块的一些簿记信息,这些信息可能是剩余的未使用的内存块。

在向缓冲区复制太多字符时,程序也可能崩溃。如果额外的字符位于堆之外,当您试图写入不存在的内存时,可能会遇到访问冲突。

malloc/free的一个实现如下所示:

通过sbrk() (Unix调用)从操作系统获取一块内存。 在该内存块周围创建一个页眉和页脚,并提供一些信息,如大小、权限以及下一个和上一个块的位置。 当传入对malloc的调用时,引用一个指向适当大小的块的列表。 然后返回这个块,页眉和页脚也相应地更新。

这与malloc和free没有特别的关系。你的程序在复制字符串后表现出未定义的行为——它可能在那一点或之后的任何一点崩溃。即使您从未使用malloc和free,并在堆栈上或静态地分配char数组,也会出现这种情况。

同样重要的是要意识到,简单地使用brk和sbrk移动程序断点指针实际上并不分配内存,它只是设置了地址空间。例如,在Linux上,当访问该地址范围时,内存将由实际的物理页“备份”,这将导致页错误,并最终导致内核调用页分配器以获得备份页。