C 这些东西的内存管理
当中各部分详细所指:
存放CPU运行的机器指令(machine instructions)。代码区一般是仅仅读的,使其仅仅读的原因是防止程序意外地改动了它的指令。
存入的是全局未初始化变量。BSS这个叫法是依据一个早期的汇编运算符而来。这个汇编运算符标志着一个块的開始。BSS区的数据在程序開始运行之前被内核初始化为0或者空指针(NULL)。
用于动态内存分配。堆在内存中位于bss区和栈区之间。一般由程序猿分配和释放,若程序猿不释放。程序结束时有可能由OS回收。
由编译器自己主动分配释放,存放函数的參数值、局部变量的值等。
其操作方式类似于数据结构中的栈。
之所以分成这么多个区域,主要基于下面考虑:
一个进程在运行过程中。代码是依据流程依次运行的。仅仅须要訪问一次。当然跳转和递归有可能使代码运行多次,而数据一般都须要訪问多次,因此单独开辟空间以方便訪问和节约空间。
暂时数据及须要再次使用的代码在执行时放入栈区中,生命周期短。
全局数据和静态数据有可能在整个程序运行过程中都须要訪问。因此单独存储管理。
堆区由用户自由分配,以便管理。
样例:
二、内存分配方式
静态分配:编译器在处理程序源码时分配。
动态分配:程序在运行时调用malloc库函数申请分配。
静态内存分配是在程序运行之前进行的因而效率比較高。而动态内存分配则能够灵活的处理未知数目的。
静态与动态内存分配的主要差别例如以下:
对象是没有名字的变量,须要通过指针间接地对它进行操作。
静态对象的分配与释放由编译器自己主动处理。动态对象的分配与释放必须由程序猿显式地管理。它通过malloc()和free两个函数(C++中为new和delete运算符)来完毕。
下面是採用静态分配方式的样例。
int a=100; |
此行代码指示编译器分配足够的存储区以存放一个整型值,该存储区与名字a相关联。并用数值100初始化该存储区。
下面是採用动态分配方式的样例。
p1 = (char *)malloc(10*sizeof(int));//分配得来得10*4字节的区域在堆区 |
此行代码分配了10个int类型的对象,然后返回对象在内存中的地址。接着这个地址被用来初始化指针对象p1。对于动态分配的内存唯一的訪问方式是通过指针间接地訪问,其释放方法为:
free(p1); |
三、堆栈那些事儿
- 栈是由编译器在须要时分配的,不须要时自己主动清除的变量存储区。里面的变量一般是局部变量、函数參数等。
- 堆是由malloc()函数(C++语言为new运算符)分配的内存块,内存释放由程序猿手动控制。在C语言为free函数完毕(C++中为delete)。栈和堆的主要差别有下面几点:
(1)管理方式不同。
栈编译器自己主动管理,无需程序猿手工控制;而堆空间的申请释放工作由程序猿控制。easy产生内存泄漏。
(2)空间大小不同。
栈是向低地址扩展的数据结构,是一块连续的内存区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,当申请的空间超过栈的剩余空间时,将提示溢出。因此。用户能从栈获得的空间较小。
堆是向高地址扩展的数据结构,是不连续的内存区域。由于系统是用链表来存储空暇内存地址的,且链表的遍历方向是由低地址向高地址。
由此可见,堆获得的空间较灵活,也较大。栈中元素都是一一相应的。不会存在一个内存块从栈中间弹出的情况。
(3)是否产生碎片。
对于堆来讲。频繁的malloc/free(new/delete)势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率减少(尽管程序在退出后操作系统会对内存进行回收管理)。对于栈来讲,则不会存在这个问题。
(4)增长方向不同。
堆的增长方向是向上的,即向着内存地址添加的方向;栈的增长方向是向下的。即向着内存地址减小的方向。
(5)分配方式不同。
堆都是程序中由malloc()函数动态申请分配并由free()函数释放的。栈的分配和释放是由编译器完毕的,栈的动态分配由alloca()函数完毕。可是栈的动态分配和堆是不同的,他的动态分配是由编译器进行申请和释放的,无需手工实现。
(6)分配效率不同。
栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令运行。
堆则是C函数库提供的。它的机制非常复杂,比如为了分配一块内存。库函数会依照一定的算法(详细的算法能够參考数据结构/操作系统)在堆内存中搜索可用的足够大的空间。假设没有足够大的空间(可能是因为内存碎片太多),就有须要操作系统来又一次整理内存空间。这样就有机会分到足够大小的内存,然后返回。
显然。堆的效率比栈要低得多。
四、内存管理函数
- malloc/free函数
Malloc()函数用来在堆中申请内存空间,free()函数释放原先申请的内存空间。
Malloc()函数是在内存的动态存储区中分配一个长度为size字节的连续空间。
其參数是一个无符号整型数,返回一个指向所分配的连续存储域的起始地址的指针。
当函数未能成功分配存储空间时(如内存不足)则返回一个NULL指针。
因为内存区域总是有限的,不能无限制地分配下去,并且程序应尽量节省资源。所以当分配的内存区域不用时,则要释放它。以便其它的变量或程序使用。
须要特别注意以下几点:
(1)调用free()释放内存后。不能再去訪问被释放的内存空间。
内存被释放后,非常有可能该指针仍然指向该内存单元,但这块内存已经不再属于原来的应用程序,此时的指针为悬挂指针(能够赋值为NULL)。
(2)不能两次释放同样的指针。
由于释放内存空间后,该空间就交给了内存分配子程序,再次释放内存空间会导致错误。
也不能用free来释放非malloc()、calloc()和realloc()函数创建的指针空间。在编程时,也不要将指针进行自加操作,使其指向动态分配的内存空间中间的某个位置。然后直接释放,这样也有可能引起错误。
(3)在进行C语言程序开发中,malloc/free是配套使用的。即不须要的内存空间都须要释放回收。
- realloc--更改已经配置的内存空间
此函数定义例如以下:
void *realloc(void *ptr,size_t size) |
參数ptr为先前由malloc、calloc和realloc所返回的内存指针,而參数size为新配置的内存大小
ptr=realloc(ptr,new_amount) |
假设内存降低。malloc只改变索引信息。但并不代表被降低的部分还能够訪问。这一部分内存将交给系统内存分配子程序。
- 其它内存管理函数calloc和alloca
返回值:若分配成功返回指针。失败则返回NULL。
它与malloc()函数的差别主要在于:
alloca是向栈申请内存。无需释放。malloc申请的内存位于堆中,终于须要函数free来释放。
malloc函数并没有初始化申请的内存空间。因此调用malloc()函数之后,还需调用函数memset初始化这部分内存空间;alloca则将初始化这部分内存空间为0。
最新文章
- oracle job的写法
- python字符串函数
- NYOJ之括号配对问题
- Struts和SpringMVC两种MVC框架比较
- JQuery html API支持解析执行Javascript脚本功能实现-代码分析
- java web sql注入测试(2)---实例测试
- BZOJ 1513 [POI2006]Tet-Tetris 3D
- J2EE开发实战基础系列一 HelloWorld【转】
- 彻底解决_OBJC_CLASS_$_某文件名";, referenced from:问题转
- SQL 获取 IDENTITY 三种方法 SCOPE_IDENTITY、IDENT_CURRENT 和 @@IDENTITY的区别
- Java多线程读书笔记之一
- javascript事件详解1
- html5本地数据库(一)
- Go语言Eclipse开发环境配置-Windows
- vijos 1067 Warcraft III 守望者的烦恼 矩阵
- jQuery给table中的负数标红色
- 慕课网-前端JavaScrpt基础面试技巧-学习笔记
- C#图解教程 第二十三章 预处理指令
- Autoit 实现word拆分页解析 (python同理)
- 清除cookie
热门文章
- tshark命令行的使用(转)
- iOS相机去黑框
- Timus 1777. Anindilyakwa 奇怪的问题计数
- Cocos2d-x学习笔记(五岁以下儿童) 精灵两种方式播放动画
- android生成apk包出现Unable to add &;quot;XXX&;quot; Zip add failed问题
- 一个小的日常实践——高速Fibonacci数算法
- 一切从编辑器说起:web前端代码编辑器
- 从Java到C++——从union到VARIANT与CComVariant的深层剖析
- Could not drop object &;#39;student&;#39; because it is referenced by a FOREIGN KEY constraint
- IE8/IE9无法启用JavaScript怎么办