C语言深度剖析-----内存管理的艺术
2016-03-04 08:43
477 查看
动态内存分配
为什么使用动态内存分配
![](http://img.blog.csdn.net/20160307132710061?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
例:记录卖出的商品
![](http://img.blog.csdn.net/20160307132703554?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](http://img.blog.csdn.net/20160307132707007?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
卖出商品最多只能记录1000个
两种改进的方法
![](http://img.blog.csdn.net/20160307132713336?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
都需要动态内存分配
第二种方法需要重置内存
![](http://img.blog.csdn.net/20160307132716889?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](http://img.blog.csdn.net/20160307132720414?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
calloc和realloc
![](http://img.blog.csdn.net/20160307132723561?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
realloc重置内存空间
例
![](http://img.blog.csdn.net/20160307132726773?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
小结
![](http://img.blog.csdn.net/20160307132733421?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
malloc(0)申请内存
首先:
在标准的malloc实现中,并不检查输入值的大小,而是将输入值做对齐操作后直接从堆上分配空间。
其次:
不论输入值的大小为多少,在malloc的内部最小的内存分配大小是一个定值(一般是8B),因为malloc需要用这部分空间来维护堆上的内存块链表。所以当用户申请一块0B的空间时,malloc实际分配的空间是8B,如果用户申请的空间是X,则malloc实际分配的空间是(对齐(X) + 8)。这也是为什么malloc分配的空间千万不能越界使用的原因:堆的内部链表结构将被破坏。
另外对于new和delete malloc和free这样的内存分配与释放函数:到底delete和free是怎么知道要释放掉多少内存的呢?
其实在new和malloc内存分配成功时,系统出除了返回一个指向这块内存的指针外,还会获得一块用于记录此处分配的内存大小的内存块:
![](http://pic002.cnblogs.com/images/2011/316345/2011080915311345.gif)
程序中的三国天下
程序中的栈
![](http://img.blog.csdn.net/20160307132845212?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](http://img.blog.csdn.net/20160307132848624?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
调用f
![](http://img.blog.csdn.net/20160307132852119?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
返回后栈空间自动清除
堆
![](http://img.blog.csdn.net/20160307132855374?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
堆空间在主动释放前一直有效,动态内存分配
![](http://img.blog.csdn.net/20160307132858791?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](http://img.blog.csdn.net/20160307132902234?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
寻找链表上内存相近的链表,删除链表,取地址指针
![](http://img.blog.csdn.net/20160307132905744?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
free(p)则在链表上插入链表,返回地址
程序中的静态存储区
![](http://img.blog.csdn.net/20160307132909947?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
小结
![](http://img.blog.csdn.net/20160307132914135?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
程序的内存布局
程序文件的一般布局
![](http://img.blog.csdn.net/20160307133233890?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
.bss段存储无初始值的变量和静态变量
![](http://img.blog.csdn.net/20160307133238782?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
左可执行程序,右执行后的内存空间布局
![](http://img.blog.csdn.net/20160307133242577?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](http://img.blog.csdn.net/20160307133245954?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
段错误
为什么使用动态内存分配
例:记录卖出的商品
卖出商品最多只能记录1000个
两种改进的方法
都需要动态内存分配
第二种方法需要重置内存
calloc和realloc
realloc重置内存空间
例
小结
malloc(0)申请内存
首先:
在标准的malloc实现中,并不检查输入值的大小,而是将输入值做对齐操作后直接从堆上分配空间。
其次:
不论输入值的大小为多少,在malloc的内部最小的内存分配大小是一个定值(一般是8B),因为malloc需要用这部分空间来维护堆上的内存块链表。所以当用户申请一块0B的空间时,malloc实际分配的空间是8B,如果用户申请的空间是X,则malloc实际分配的空间是(对齐(X) + 8)。这也是为什么malloc分配的空间千万不能越界使用的原因:堆的内部链表结构将被破坏。
另外对于new和delete malloc和free这样的内存分配与释放函数:到底delete和free是怎么知道要释放掉多少内存的呢?
其实在new和malloc内存分配成功时,系统出除了返回一个指向这块内存的指针外,还会获得一块用于记录此处分配的内存大小的内存块:
![](http://pic002.cnblogs.com/images/2011/316345/2011080915311345.gif)
程序中的三国天下
程序中的栈
调用f
返回后栈空间自动清除
堆
堆空间在主动释放前一直有效,动态内存分配
寻找链表上内存相近的链表,删除链表,取地址指针
free(p)则在链表上插入链表,返回地址
程序中的静态存储区
小结
程序的内存布局
程序文件的一般布局
.bss段存储无初始值的变量和静态变量
左可执行程序,右执行后的内存空间布局
段错误
指针其实适合普通的变量一样的,你把它当作一个 int类型的数就行了。 变量的保存位置: 全局变量和静态变量都是保存在数据段。 普通变量 如果是自己用 new () 申请的 ,会保存在 堆里面。 其他的函数里面的局部变量,一般被优化成对 寄存器的访问,如果寄存器分配完了,就会保存在栈里面,有函数调用的时候,改变指针时留出空间。
函数的地址对应程序的代码段地址
为什么初始化和未初始化的全局变量存储在不同段?
C规定,未初始化变量的初值为0,这个清0的操作是由启动代码完成的,还有已初始化变量的初值的设置,也是由启动代码完成的。 为了启动代码的简单化,编译链接器会把已初始化的变量放在同一个段:.data,这个段的映像(包含了各个变量的初值)保存在“只读数据段”,这样启动代码就可以简单地复制这个映像到 .data 段,所有的已初始化变量就都初始化了。 而未初始化变量也放在同一个段:.bss,启动代码简单地调用 memset 就可以把所有未初始化变量都清0。 头疼的野指针没有任何手段判断一个指针是否为野指针 野指针的由来
![]()
![]()
![]()
经典错误
出错分别对应d1.p d2.p
![]()
内存泄漏分析
奇数会造成内存泄漏,会逐渐占用内存,导致重启
改正
遵循单入口单出口原则 多次指针释放
谁申请谁释放会Aborted异常退出 使用已释放的指针
C语言中的交通规则0地址一般为操作系统操作的,如果破坏操作系统的内存区,会操作系统会把程序干掉
![]()
![]()
改正
![]()
指针只有NULL和有地址,某种意义上杜绝野指针
相关文章推荐
- [C语言][LeetCode][21]Merge Two Sorted Lists
- c++ socket 客户端库 socks5 客户端 RudeSocket™ Open Source C++ Socket Library
- 三种工厂模式的分析以及C++实现
- C++栈(stack)
- [C++11]_[初级]_[weak_ptr的使用场景]
- [C++11]_[初级]_[weak_ptr的使用场景]
- C/C++程序员必须熟练应用的开源项目
- C++封装继承多态总结
- C++ 虚函数 重载 重写的区别(转)
- C语言实现栈
- C语言实现二叉树并且实现二叉树的遍历
- 《Effective C++》学习笔记——条款40
- 双向链表的C++实现
- C++中关于类(封装、继承、多态)区别于结构体的理解
- C++ LNK 2001 LNK 2019 LNK 2028 LNK 2029链接错误
- 动态内存分配(c语言)
- [C++11]_[初级]_[unique_ptr的使用场景]
- [C++11]_[初级]_[unique_ptr的使用场景]
- c、OC、C++的三种预处理功能
- 嵌入式C语言常见面试题分析