关于C++内存分配的一些总结
来源:互联网 发布:95579交易软件下载 编辑:程序博客网 时间:2024/06/04 17:59
之前一段时间翻阅过一些内存分配的资料,这次终于能将其整理记录下来了。
c标准库里有两个耳熟能详的函数,用于对堆空间的内存进行分配和释放,它们分别是:
- malloc。负责分配一个指定大小的一块内存给调用的程序,函数返回一个指向这块内存的指针。
- free。对函数参数指向的内存块进行释放操作。
需要说明的是,不管是malloc还是free,这些函数都是c标准库提供给我们的,而不是操作系统的API。对于堆上的内存管理,操作系统(Linux)提供以下两个接口:
- sbrk。用于扩张和收缩堆,本质上就是移动指向堆顶的指针。把指针向高地址移动就是在扩张堆、向低地址移动就是在收缩堆。
- mmap、munmap。用于内存映射和取消内存映射,对于大块的内存申请,直接调用mmap申请一个内存段更加高效。
显然,malloc的实现是基于操作系统提供的API的,也就是上面提到的那两个syscall。而且,一般考虑到会频繁的进行内存分配,我们往往希望能尽量减少syscall的次数。于是,通常的策略是如下。
一般地,实现会在内部维持了一个空闲内存块的链表,当我们通过malloc申请一块内存,我们先在这个链表里进行搜索,如果找到符合大小的内存块,就将这个内存块返回给调用程序。否则,当在空闲链表中搜索不到满足要求的内存块,说明当前堆的大小不够用了,调用syscall以扩张堆的大小,并重新搜索内存块。当通过free释放内存的时候,则将内存块返回给这个空闲链表。空闲链表可能会有一些策略,用来在未来的某一个时候,通过syscall将这些空闲的内存重新归还给操作系统。
不同的malloc/free的实现,主要是在如何组织这个空闲内存块的链表上有所不同。关于glibc的malloc可以参考这篇文章:Glibc内存管理。
在清楚malloc内部做了什么之后,就可以搞明白一些诡异的问题了。比如说,重新引用一块已经free掉的内存,为什么有时候会报段错误,有时候会崩溃,有时候什么事都没发生?
首先要说明的是操作系统的内存管理是段页式的,既分段也分页。而通常一个程序的内存段有:代码段、静态数据全局数据段、堆、栈等,而程序所能访问的地址必须是在OS已经分配的内存段中。如果访问的地址不在已存在的段内,就会报我们熟悉的段错误。当通过free将内存释放时,分配程序有可能为了重新利用这块内存而缓存着它,也有可能将这块内存真正的归还给操作系统。如果内存块被真正的归还给操作系统,比如free操作导致了堆的收缩,或是在free中调用了munmap取消了一个内存映射。这时候如果有一个指针指向这块内存地址,对它引用就会导致段错误。
不过大多数情况下,free掉的内存块不是立即归还给OS,而是被分配程序(malloc)插入到空闲内存块链表中缓存起来,等待再次被利用。有的实现(例如glibc的ptmalloc)为了内存空间的复用,会在这个内存块里面记录下指向链表前后节点的指针等信息。这时候如果我们对free掉的内存块重新执行写操作就有可能会改写这部分信息,导致这个内存块被写坏,破坏了空闲链表的结构,因此就有可能引起崩溃。
- 关于C++内存分配的一些总结
- C语言------关于系统内存分配机制的一些整理
- 关于C语言变量内存分配一些自己的理解。
- C\C++编译器关于变量的内存分配顺序总结
- C\C++编译器关于变量的内存分配顺序总结
- C\C++编译器关于变量的内存分配顺序总结
- 关于内存分配的一些问题
- c/c++关于内存分配的知识
- C关于内存分配的错误解析
- c/c++关于内存分配的知识
- 关于Linux C 程序的内存分配
- C语言中关于内存的分配
- 关于内存的分配
- 关于全局变量指针直接 malloc分配内存的一些问题
- C下内存分配的一些知识【VS2010下测试】
- C的内存分配
- 关于java对象内存的一些总结
- 关于内存对齐的一些总结
- 海明码校验程序设计
- SQL优化之六脉神剑
- iOS启动页加载静态图和动态图
- java打印数组内容
- 人工智能技术让城市更加安全,便捷,智慧 | 千视通参加贵阳视频侦查研修班
- 关于C++内存分配的一些总结
- string、char*、CString之间的转换
- Lintcode 上一个排列
- opencv 霍夫变换检测圆环
- word实现文献引用2
- Sampled Softmax 论文笔记:On Using Very Large Target Vocabulary for Neural Machine Translation
- nginx中root和alias的区别
- spring data jps
- CRC校验程序设计