深入理解C指针之二:C内存管理
内存管理对所有程序来说都很重要。有时候内存由运行时系统隐式的管理,比如为变量自动分配内存。在这种情况下,变量分配在它所处的函数的栈帧上(每个函数都有它自己的栈帧,用来保存它的局部变量和返回地址等)。如果是静态或全局变量,内存处于程序的数据段,会被自动清零。数据段是一个区别于可执行代码和运行时系统管理的其它数据的内存区域。
C语言也支持动态内存管理,对象就是从堆上分配出来的内存。这是用分配和释放函数手动实现的,这个过程被称为动态内存管理。在C中动态分配内存的基本步骤有:
1、用malloc类的函数分配内存;
2、用这些内存支持应用程序;
3、用free函数释放内存。
int* pi = (int*) malloc (sizeof(int));
*pi = 5;
printf(" pi is : %d\n address : %p\n", *pi, pi);
free(pi);
// pi is : 5
// address : 0x8843008
malloc函数的参数指定要分配的字节数。如果成功则返回从堆上分配的内存的指针,如果失败则返回空指针。sizeof操作符能确定在宿主系统中应该分配的正确字节数,因为在不同的系统中,数据的字节数可能是不同的。每次调用malloc或类似函数时,结尾都应有对应的free函数调用,以防止内存泄露。
如果不再使用已分配的内存却没有将其释放就会发生内存泄露,导致内存泄露的情况可能如下:
1、丢失内存地址;
2、应该调用free函数却没有调用(隐式泄露);
以下几个内存分配函数可以用来管理动态内存,大部分包含在stdlib.h头文件中:
1、malloc:从堆上分配内存
2、realloc:在之前分配的内存块的基础上,将内存重新分配为更大或更小的部分
3、calloc:从堆上分配内存并清零
4、free:将内存块返回堆
动态内存从堆上分配,对于一连串内存分配调用,系统不保证内存的顺序和所分配内存的连续性。不过,分配的内存会根据指针的数据类型对齐,比如4字节的整数会分配在能被4整除的地址边界上。堆管理器返回的地址是最低字节的地址。
malloc函数从堆上分配一块内存,分配的字节数由唯一的参数制定,返回值是void指针,如果内存不足,则返回NULL。此函数不会清空或修改内存,所以新分配的内存包含垃圾数据。
void* malloc(size_t);
执行malloc函数会执行以下操作:
1、从堆上分配内存;
2、内存不会被修改或者清空;
3、返回首字节的地址;
void指针可以转换成任意指针,但是显示的指针类型转换能获得对c++的更好兼容性,也能使代码更清晰。注意函数参数尽量使用sizeof操作符,而且不要试图接引一个未初始化内存数据的指针变量。
int* mpi = (int*) malloc (sizeof(int));
if(mpi!=NULL)
{
//pointer OK
}
else
{
//pointer not OK
}
初始化静态或全局变量时不能调用动态内存分配函数。但是对于静态变量,可以用一个单独的赋值语句来给变量分配内存。
static int* spi;
spi = (int*) malloc (sizeof(int));
使用calloc函数会在分配的同时清空内存。清空内存意思是将其内容置为二进制的0。
void* calloc(size_t numElements, size_t elementSize);
calloc函数根据两个参数的乘积来分配内存,并返回指向内存的第一个字节的指针。如果不能分配内存,则会返回NULL。执行calloc可能比malloc慢,因为它要做额外的内存清理工作。
如果需要增加或减少为指针分配的内存,可以使用realloc函数。
void* realloc(void* ptr, size_t size);
第一个参数是指向原内存快的指针,第二个是请求的大小。返回值是指向重新分配的内存的指针。如果请求的新内存大小比原来的小,多余的内存会返还给堆。如果比原来的大,可能的话,会紧挨着当前分配的内存区域分配新的内存,否则会在堆的其它区域分配并把就的内存复制到新区域。如果请求大小是0,那么就释放内存。如果无法分配,则返回空指针。注意永远不要使用超出内存分配的地址。
使用free函数将不再使用的内存返还给系统。
void free(void* ptr);
指针参数应该指向由malloc函数分配的内存,这块内存会被返还给堆。尽管该指针仍然指向该内存,但是该内存现在被认为包含垃圾数据,并且可能被写入新的数据。该指针则称为迷途指针。注意空指针不指向任何东西,迷途指针还是指向一个地址。如果是在一个函数里面分配的内存,那么就应该在同一个函数里面释放它。
重复释放是指两次释放同一块内存。第二次调用free会引发运行时异常。两个指针指向同一个内存地址称为别名。别名可能导致重复释放。堆管理器不一定会在free函数后将内存返回给操作系统,而是可能给程序后续使用。
迷途指针是指访问已释放的内存的指针。使用迷途指针会导致不可预期的行为和潜在的安全隐患。在指针别名的情况下,迷途指针更难以察觉。
int *gpi;
{
int tmp = 5;
*gpi = &tmp;
}
大部分编译器把块语句当做一个栈帧。在块语句退出是,分配在栈帧上的tmp会出栈,gpi变成迷途指针,指向一块已经被自动回收的内存。
除了使用函数手动分配内存外,还有一些非标准技术可以用来实现C的动态内存管理。这些技术的关键特性在于自动释放内存。内存不再使用之后会被收集起来备用,释放的内存成为垃圾,因此这个过程也叫垃圾回收。垃圾回收使程序员不必费心考虑何时释放内存,更专注程序本身的问题。垃圾回收技术包括RAII和异常处理等。
深入理解C指针之二:C内存管理的更多相关文章
- 03深入理解C指针之---变量与内存
该系列文章源于<深入理解C指针>的阅读与理解,由于本人的见识和知识的欠缺可能有误,还望大家批评指教. C语言是一种编译型的语言,C源代码在编译成可执行文件后,经常以以下三种方式使用内存: ...
- Block介绍(二)内存管理与其他特性
我们在前一章介绍了block的用法,而正确使用block必须要求正确理解block的内存管理问题.这一章,我们只陈述结果而不追寻原因,我们将在下一章深入其原因. 一.block放在哪里 我们针对不同情 ...
- iOS中Block介绍(二)内存管理与其他特性
我们在前一章介绍了block的用法,而正确使用block必须要求正确理解block的内存管理问题.这一章,我们只陈述结果而不追寻原因,我们将在下一章深入其原因. 一.block放在哪里 我们针对不同情 ...
- 《Linux内核设计与实现》读书笔记(十二)- 内存管理【转】
转自:http://www.cnblogs.com/wang_yb/archive/2013/05/23/3095907.html 内核的内存使用不像用户空间那样随意,内核的内存出现错误时也只有靠自己 ...
- # 深入理解Redis(二)——内存管理的建议与技巧
引语 随着使用Redis的深入,我们不可避免的需要深入了解优化Redis的内存,本章将重点讲解Redis的内存优化之道,同时推荐大家阅读memory-optimization一文. 想要高效的使用Re ...
- c++ boost库学习二:内存管理->智能指针
写过C++的人都知道申请和释放内存组合new/delete,但同时很多人也会在写程序的时候忘记释放内存导致内存泄漏.如下所示: int _tmain(int argc, _TCHAR* argv[]) ...
- Block(二)内存管理与其他特性
一.block放在哪里 我们针对不同情况来讨论block的存放位置: 1.栈和堆 以下情况中的block位于堆中: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ...
- Block(二)内存管理与其他特性-b
一.block放在哪里 我们针对不同情况来讨论block的存放位置: 1.栈和堆 以下情况中的block位于堆中: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ...
- MySQL 调优基础(二) Linux内存管理
进程的运行,必须使用内存.下图是Linux中进程中的内存的分布图: 其中最重要的 heap segment 和 stack segment.其它内存段基本是大小固定的.注意stack是向低地址增长的, ...
随机推荐
- webclient下载文件 带进度条
private void button1_Click(object sender, EventArgs e) { doDownload(textBox1.Text.Trim()); } private ...
- window下自己主动备份数据库成dmp格式的bat写法
复制以下的命令到一个txt文本文档,然后改动相应的參数为自己须要的參数,一切完毕之后,将文件保存为bat格式. 这样每次须要备份的时候仅仅须要双击一下这个bat文件.其它的都不用你了,你仅仅须要静静的 ...
- c# 判断字符是否是全角, 获取字符串的字节数 , 获取字符串指定长度字节数的字符串
1 Encoding.Default.GetByteCount(checkString); =2 全角 =1 半角 /// <summary> /// 获取字符串的字节长度 /// &l ...
- Tomcat通过配置一个虚拟路径管理web工程
关于虚拟路径.学问javaweb训练课程,如今,鉴于这种情况下老师. 当我们的项目,当在不同的文件夹项目.我们如何使用tomcat去管理web工程. 教师提出的解决方案是 使用虚拟路径方式,并按照实施 ...
- ym——Android之ListView性能优化
转载请注明本文出自Cym的博客(http://blog.csdn.net/cym492224103),谢谢支持! Android之ListView性能优化 假设有看过我写过的15k面试题的朋友们一定知 ...
- expandableListView的divider该溶液显示在黑色
黑色是divider高度.如何让他成为透明的啊? 布局例如以下: <ExpandableListView android:layout_width="wrap_content&qu ...
- POJ 2226 Muddy Fields(最小顶点覆盖)
POJ 2226 Muddy Fields 题目链接 题意:给定一个图,要求用纸片去覆盖'*'的位置.纸片能够重叠.可是不能放到'.'的位置,为最少须要几个纸片 思路:二分图匹配求最小点覆盖.和放车那 ...
- 2014.06.14 GlusterFS技术交流视频
6月14线下GlusterFS视频交流.高清视频是非常好的,我初听言论方面,谈到迅速,似乎不是很清楚,讲座结束后速度需要改进.谢谢能力的天空AbleSky高大内设,谢谢学生参加. 在线公开课:http ...
- Android虚拟机器学习总结Dalvik虚拟机创建进程和线程分析
Dalvik调用一个成员函数时,虚拟机,假设发现,该成员函数是一个JNI办法,然后,它会直接跳转到其地址来运行.也就是说.JNI方法是直接在本地操作系统上运行的.而不是由Dalvik虚拟机解释器运行. ...
- Visual Studio Team Services使用教程--默认团队权限说明