嵌入式Linux上C语言编程实践--第9章 动态内存堆与栈.ppt
第四部分 C语言高级编程 第9章 动态内存的堆与栈 第10章 函数指针的使用 第11章 回调函数的使用 第12章 C语言实现对象编程 在嵌入式C语言程序开发中,一个非常重要的内容就是内存的使用,尤其是动态内存的使用。 C语言中动态内存主要使用堆和栈来实现。 本章主要内容: C语言中程序的存储区域 动态内存的堆与栈的特性 C语言语言与堆、栈的对应关系 堆和栈使用的对比 9.1 程序内存区域的使用 9.1.1 静态内存与动态内存 C语言程序中数据所使用的内存分类: 静态数据存储区 只读数据区(RO Data) 已初始化的读写数据区(RW Data) 未初始化的读写数据区(BSS) 它们都是在程序的编译-连接阶段确定的,在程序运行的初始化阶段,静态存储区将在内存中开辟,其大小和位置在程序的运行过程中都是固定不变的,仅当程序结束时才会被系统收回。 动态数据存储区: 栈(stack) 堆(heap) 它们是在程序运行过程中动态分配的,其大小将在程序运行过程动态地变化。 典型的动态内存管理形式:堆内存和栈内存的分配方向通常是相向的 栈内在从高地址向低地地址分配 堆内存从低地址向高地址分配 动态内存的存储结构 栈 使用线性存储的方式 堆 使用链表来实现 C语言程序的存储区如图9-1所示。 9.1.2 C语言中的动态内存 1.栈内存 栈是一种先入后出FILO(后进先出LIFO)的内存区域。 栈内存由编译器管理 栈内存对应内存中的一块区域,有大小限制。 栈内存的使用依赖于处理器的硬件机制--栈指针寄存器。 栈指针是一个指向栈内部区域的指针,它的值为一个地址,位于栈内存的上、下界之间。 栈指针将栈区域分为两个部分: 已使用区域 未使用区域 栈内存的增长(生长)方向: 向上增长(生长) 向下增长(生长) 栈指针的变化 在向下增长的栈中,初始时栈指针是指向栈的上界(高地址端),随着入栈数据的增加,栈指针将向低地址端变化,即栈指针将变小。在向上增长的栈中则相反。 栈内存的重要特性:后进先出(LIFO) 栈内存的基本操作: 入栈(PUSH) 出栈(POP) 入栈、出栈过程(以向下增长的满栈为例) 入栈:先修改指针,再放内容,入栈后,指针指向刚入栈的数据 出栈:先取内容,再修改指针,指向下一个要出栈的数据 只能对栈顶数据进行操作。 栈内存是一端固定(栈底),一端浮动(栈顶)的。 空栈和满栈 空栈:栈指针所指的位置没有数据。入栈时,先放数据,后修改指针,出栈时,先修改指针,再取数据。 满栈:栈指针所指的位置总有数据(刚入栈的数据或将要取出的数据) 一个系统是满栈 or 空栈是由处理器结构决定的,与程序的编写无关。 前面演示的是满栈的情况 栈总结: 综合栈的生长方向和指针所指单元是否使用,栈可分为四种情况: 满递增栈:入栈时,指针先增加,再放数据,入栈后,栈指针指向刚入栈的数据;出栈时,先取数据,指针再减少,出栈后栈指针指向下一数据。 满递减栈:入栈时,指针先减小,再放数据,入栈后,栈指针指向刚入栈的数据;出栈时,先取数据,指针再增加,出栈后栈指针指向下一数据。 空递增栈:入栈时,先放数据,指针再增加,入栈后,栈指针指向一个新的空位置;出栈时,指针先减少,再取数据,出栈后栈指针指向的位置的数据已被取出(空位置)。 空递减栈:入栈时,先放数据,指针再减小,入栈后,栈指针指向一个新的空位置;出栈时,指针先增加,再取数据,出栈后栈指针指向的位置的数据已被取出(空位置)。 2.堆内存 在一般的编译系统中,堆内存的分配方向和栈内存是相向的:如,栈内存从高地址向低地址增长时,堆内存便从低地址向高地址分配。 在C语言中,堆内存的分配和释放是通过程序调用C语言的库函数(malloc()、calloc()、realloc())来实现的。而栈内存是使用处理器的硬件机制实现的。 堆内存的分配过程: 分配:每调用一次malloc()函数,都将返回一个当前分配到的内存区域的首地址(指针),根据指针可访问分配到的堆内存空间 释放:调用free()函数可释放用malloc()函数分配到的内存,不影响其他未释放的堆内存区域的使用。 栈内存和堆内存在分配和使用上的区别: 栈内存只有一个入口点--栈指针,它的位置是已使用区和未使用区的界限,栈的访问只能通过栈指针及偏移量进行 堆内存可有多个入口点,每次分配得到的指针都是访问的入口点,每个指针指向的区域可被单独释放。 堆内存的分配原则: 堆内存的分配是从堆内存的低地址端开始进行分配,如果低地址端找不到一个满足要求的连续区域,将到较高地址端去分配,直到分配成功时返回分配的内存区域的首地址,或失败时返回NULL。 内存碎片 频繁采用malloc()和free()函数进行不同大小的内存分配和释放操作,将会在内存