原文:深入理解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内存管理的更多相关文章

  1. 03深入理解C指针之---变量与内存

    该系列文章源于<深入理解C指针>的阅读与理解,由于本人的见识和知识的欠缺可能有误,还望大家批评指教. C语言是一种编译型的语言,C源代码在编译成可执行文件后,经常以以下三种方式使用内存: ...

  2. Block介绍(二)内存管理与其他特性

    我们在前一章介绍了block的用法,而正确使用block必须要求正确理解block的内存管理问题.这一章,我们只陈述结果而不追寻原因,我们将在下一章深入其原因. 一.block放在哪里 我们针对不同情 ...

  3. iOS中Block介绍(二)内存管理与其他特性

    我们在前一章介绍了block的用法,而正确使用block必须要求正确理解block的内存管理问题.这一章,我们只陈述结果而不追寻原因,我们将在下一章深入其原因. 一.block放在哪里 我们针对不同情 ...

  4. 《Linux内核设计与实现》读书笔记(十二)- 内存管理【转】

    转自:http://www.cnblogs.com/wang_yb/archive/2013/05/23/3095907.html 内核的内存使用不像用户空间那样随意,内核的内存出现错误时也只有靠自己 ...

  5. # 深入理解Redis(二)——内存管理的建议与技巧

    引语 随着使用Redis的深入,我们不可避免的需要深入了解优化Redis的内存,本章将重点讲解Redis的内存优化之道,同时推荐大家阅读memory-optimization一文. 想要高效的使用Re ...

  6. c++ boost库学习二:内存管理->智能指针

    写过C++的人都知道申请和释放内存组合new/delete,但同时很多人也会在写程序的时候忘记释放内存导致内存泄漏.如下所示: int _tmain(int argc, _TCHAR* argv[]) ...

  7. Block(二)内存管理与其他特性

    一.block放在哪里 我们针对不同情况来讨论block的存放位置: 1.栈和堆 以下情况中的block位于堆中: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ...

  8. Block(二)内存管理与其他特性-b

    一.block放在哪里 我们针对不同情况来讨论block的存放位置: 1.栈和堆 以下情况中的block位于堆中: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ...

  9. MySQL 调优基础(二) Linux内存管理

    进程的运行,必须使用内存.下图是Linux中进程中的内存的分布图: 其中最重要的 heap segment 和 stack segment.其它内存段基本是大小固定的.注意stack是向低地址增长的, ...

随机推荐

  1. linux 下修改 apache 启动的所属用户和组

    apache默认启动的用户和组是www-data,所以有些时候,就会涉及到权限问题,没有权限在执行目录下创建或者读写文件.改变用户和组的方法其实很简单: 1.进入到apache默认安装路径/etc/a ...

  2. (4)通过调用hadoop的java api实现本地文件上传到hadoop文件系统上

    (1)首先创建java project 选择eclipse菜单上File->New->Java Project. 并命名为UploadFile. (2)加入必要的hadoop jar包 右 ...

  3. jquery之ajax中国乱码的解决方案

    $.ajax({ dataType : 'json',type : 'POST',url : 'http://localhost/test/test.do',data : {id: 1, type: ...

  4. Asp.net中Postback及Callback

    我们知道,在默认的情况下,当我们点击Asp.net Page中的一个服务器Button时(默认其实是Submit Form),会导致Page被Recreated,这个过程我们称之为Postback,它 ...

  5. 移动端 transition动画函数的封装(仿Zepto)以及 requestAnimationFrame动画函数封装(仿jQuery)

    移动端 css3 transition 动画 ,requestAnimationFrame 动画  对于性能的要求,h5优先考虑: 移动端 单页有时候 制作只用到简单的css3动画即可,我们封装一下, ...

  6. java假设去请求一个网页的数据

    我们能够通过在java程序中模拟浏览器一样,把数据抓下来,详细方法是在java程序中set header和cookie,以下是一个样例: public class NetConnection { pu ...

  7. How to Use NSLog to Debug CGRect and CGPoint

    转载:  http://iosdevelopertips.com/debugging/how-to-use-nslog-to-debug-cgrect-and-cgpoint.html CGPoint ...

  8. 2年SQL Server DBA调优方面总结

    原文:2年SQL Server DBA调优方面总结 2年SQL Server DBA调优方面总结 当2年dba 我觉得,有些东西需要和大家分享探讨,先书单. 书单 1.<深入解析SQL Serv ...

  9. Android:抄QQ照片选择器(按相册类别显示,加入选择题)

    这个例子的目的是为了实现类似至QQ照片选择功能.选择照片后,,使用类似新浪微博 微博 页面上显示. 先上效果图:     本例中使用的主要技术: 1.使用ContentProvider读取SD卡全部图 ...

  10. .NET反编译之Reflector

    .NET反编译之Reflector 这几日由于公司需要, 看了些.NET反编译技巧,特地和大家分享下 .NET反编译工具很多,Reflector是其中一个很优秀的工具,所以就用它来进行反编译工作了.今 ...