c语言内存管理及经典算法

上传人:第*** 文档编号:38764032 上传时间:2018-05-07 格式:DOCX 页数:77 大小:236.52KB
返回 下载 相关 举报
c语言内存管理及经典算法_第1页
第1页 / 共77页
c语言内存管理及经典算法_第2页
第2页 / 共77页
c语言内存管理及经典算法_第3页
第3页 / 共77页
c语言内存管理及经典算法_第4页
第4页 / 共77页
c语言内存管理及经典算法_第5页
第5页 / 共77页
点击查看更多>>
资源描述

《c语言内存管理及经典算法》由会员分享,可在线阅读,更多相关《c语言内存管理及经典算法(77页珍藏版)》请在金锄头文库上搜索。

1、C 语言内存管理对于一个 c/c+程序员来说,内存泄漏是一个常见的也是令人头疼的问题,为了应对这 个问题,有许多技术被研究出来来解决这个问题,例如 Smart Pointer,Garbage Collection 等。 一般我们常说的内存泄漏是指堆内存的泄漏。那么为什么会导致内存泄漏呢?通过学习内 存管理,相信你一定能解决好这个问题。1-1C 语语言内存管理方式言内存管理方式在进入本专题前,我们先看一下下面的程序,来简单分析以下 C 语言的内存管理:#include #include /全局变量定义 int iGlobalInt1=0;int iGlobalInt2=0;int iGlobal

2、Int3=0;/全局常量定义 const int iGlobalConstInt1=1;const int iGlobalConstInt2=5;const int iGlobalConstInt3=6;/全局静态变量定义 static int iGlobalStaticInt1=0;static int iGlobalStaticInt2=0;static int iGlobalStaticInt3=0;/函数定义 void funcParamTest(int iFuncParam1,int iFuncParam2,int iFuncParam3) /函数私有变量定义int iLocalIn

3、t1=iFuncParam1;int iLocalInt2=iFuncParam2;int iLocalInt3=iFuncParam3;printf(“函数参数变量内存地址n“);printf(“iFuncParam1=0x%08xn“,printf(“iFuncParam2=0x%08xn“, printf(“iFuncParam3=0x%08xnn“, printf(“函数本地变量的内存地址n“);printf(“iLocalInt1=0x%08xn“, printf(“iLocalInt2=0x%08xn“, printf(“iLocalInt3=0x%08xnn“, return;

4、/入口函数 int main(int argc, char* argv)/局部静态变量 static int iStaticInt1=0;static int iStaticInt2=0;static int iStaticInt3=0;/局部静态常量定义 const static int iConstStaticInt1=0;const static int iConstStaticInt2=0;const static int iConstStaticInt3=0;/局部常量 const int iConstInt1=1;const int iConstInt2=5;const int i

5、ConstInt3=6;/局部变量 int iLocalInt1=0;int iLocalInt2=0;int iLocalInt3=0;char * pMalloc1,*pMalloc2,*pMalloc3;char * pNew1,*pNew2,*pNew3;printf(“全局常量的内存地址n“); printf(“iGlobalConstInt1=0x%08xn“, printf(“iGlobalConstInt2=0x%08xn“, printf(“iGlobalConstInt3=0x%08xnn“,printf(“iConstStaticInt1=0x%08xn“, printf

6、(“iConstStaticInt2=0x%08xn“, printf(“iConstStaticInt3=0x%08xnn“, printf(“全局变量的内存地址n“);printf(“iGlobalInt1=0x%08xn“,printf(“iGlobalInt2=0x%08xn“, printf(“iGlobalInt3=0x%08xnn“, printf(“静态变量的内存地址n“);printf(“iGlobalStaticInt1=0x%08xn“, printf(“iGlobalStaticInt2=0x%08xn“, printf(“iGlobalStaticInt3=0x%08

7、xnn“, printf(“iStaticInt1=0x%08xn“, printf(“iStaticInt2=0x%08xn“, printf(“iStaticInt3=0x%08xnn“, printf(“本地变量的内存地址n“);printf(“iConstInt1=0x%08xn“, printf(“iConstInt2=0x%08xn“, printf(“iConstInt3=0x%08xnn“,printf(“iLocalInt1=0x%08xn“, printf(“iLocalInt2=0x%08xn“, printf(“iLocalInt3=0x%08xnn“,funcPara

8、mTest(iLocalInt1,iLocalInt2,iLocalInt3);/在堆上分配内存,使用 new pNew1=new char16;pNew2=new char16;pNew3=new char16;/在堆上分配内存,使用 malloc pMalloc1 = (char *)malloc( 16 ); pMalloc2 = (char *)malloc( 16 ); pMalloc3 = (char *)malloc( 16 ); printf(“在堆上分配内存内存地址n“); printf(“pMalloc1=0x%08xn“,pMalloc1); printf(“pMallo

9、c2=0x%08xn“,pMalloc2); printf(“pMalloc3=0x%08xnn“,pMalloc3); /释放 new 分配的内存空间delete pNew1; delete pNew2; delete pNew3; pNew1=NULL;pNew2=NULL; pNew3=NULL;/释放 malloc 分配的内存空间 free(pMalloc1);free(pMalloc2);free(pMalloc3);pMalloc1=NULL;pMalloc2=NULL;pMalloc3=NULL;return 0;本程序在 Windows XP 下,VC6 编译后的执行结果是:注

10、意,上面我们输出的完全是内存地址,也就是说,是程序在进程中内存地址(注意是虚 拟内存地址而不是物理内存地址) 。我们认真观察程序输出,发现每种类型的内存地址都是 连续的,而不同类型之间内存地址有的是连续的,有的差别极大(注意:不同编译器可能 输出的结果不一样,但这并不影响我们分析问题) 。基本上,我们可以把这些地址范围分为 如下几个部分:堆、栈、全局/静态存储区和常量存储区。 栈,就是那些由编译器在需要的时候分配,在不需要的时候自动释放的存储区。里面的变 量通常是局部变量、函数参数等。在栈上分配内存,通常是指在执行函数时,函数内局部 变量在栈上创建,函数执行结束时这被自动释放。栈内存分配运算内

11、置于处理器的指令集 中,效率很高,但是分配的内存容量有限。堆,就是那些由 new 或使用 malloc 分配的内存块,他们的释放编译器不去管,由我们的应 用程序去控制,一般一个 new/malloc 就要对应一个 delete/free。如果程序员没有释放掉, 那么在程序结束后,操作系统会自动回收。动态内存的生存期由我们决定,使用非常灵活, 但问题最多,也是我们本章讨论的重点。 全局/静态存储区,全局变量和静态变量被分配到同一块内存中,在以前的 C 语言中,全局 变量又分为初始化的和未初始化的,在 C+里面没有这个区分了,他们共同占用同一块内 存区。静态存储区在程序编译的时候就已经分配好,这块

12、内存在程序的整个运行期间都存 在。 常量存储区,这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改(通过特 殊手段当然是可以修改的,例如 Windows 下可直接修改 PE 文件) 。 通过分析上面的程序,我们大抵可以绘出程序内存分配情况 栈 代码区静态数据区低端内存区域高端内存区域 常量存储区堆通过上面分析,我们知道,全局常量(例如 iGlobalConstInt1)和局部静态常量(例如 iConstStaticInt1)位于常量存储区;全局变量(例如 iGlobalInt1)和局部静态变量 (iStaticInt1)位于静态数据区;本地变量(例如 iLocalInt1)和函数参数变

13、量(例如 iFuncParam1)位于栈区,它是动态存储区的一部分;使用 malloc/new(例如 pMalloc1,pNew1)分配的内存位于堆区,它也是动态存储区的一部分。 由于常量存储区和静态数据区都是在程序编译的时候就分配好空间了,而堆栈是在程序运 行过程中自动分配好的空间。使用堆分配内存是显式分配的,我们在稍后详细介绍。下面 简单介绍一下使用栈分配内存空间的原理。我们来看看我们 DEMO 程序对于函数参数那一部分,我们发现,栈分配如下所示 iLocalInt2 = 0x0012ff3ciLocalInt3 = 0x0012ff40RETiFuncParam2 = 0x0012ff4

14、c低端内存区域高端内存区域 iFuncParam1 = 0x0012ff48iFuncParam3 = 0x0012ff50iLocalInt1 = 0x0012ff38我们发现函数参数地址和变量地址分布如上,其中多了四个字节,正好就是 RET 指令。首 先,三个参数以从又到左的次序压入堆栈,先压“iFuncParam3” ,再压“iFuncParam2” , 最后压入“iFuncParam1” ;然后压入函数的返回地址(RET),接着跳转到函数地址接着执行。 第三步,将栈顶(ESP)减去一个数,为本地变量分配内存空间,接着就初始化本地变量的内 存空间。感兴趣的读者可以使用工具反汇编上面的代码

15、,然后就可以看到 C 语言是如何编 译的了。 从上面我们可以看出,对于栈分配内存而言,是由编译器自动管理,无需我们手工控制。 然而,对于堆而言,内存分配与释放由程序员控制了,方法非常灵活,但也最容易出现问 题。1-2C 语语言内存管理言内存管理上一节中我们简单分析了 C 语言内存管理方式,其中对于堆的管理,我们仅进行了简单描 述。在本节中我们要详细描述 C 语言内存管理。在介绍之前,我们需要先熟悉 C 语言堆内 存管理涉及的函数。allocavoid * alloca( size_t size );alloca 的作用分配一块大小为 size 个字节的可用内存块,并返回首地址。不能分配的时候

16、返回 NULL。alloca 是从栈中分配内存空间,使用 alloca 分配内存后不必使用 free 来释放内 存。alloca 是分配一块未经初始化的内存,这和 malloc 一样,如果需要初始化可以调用 memset 函数。在上节中,我们已经对栈分配做了详细的描述,栈的释放是由编译器自动 管理的,所以不需要我们手动去释放它。示范代码如下:#include #include int main()int size = 1000;int errcode = 0;void *pData = NULL;if (size 0 /* Allocate space for a path name */string = malloc( _MAX_PATH );/ In a C+ file, explicitly cast mallo

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 学术论文 > 毕业论文

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号