C++:内存分配

来源:互联网 发布:淘宝卖家数据分析 编辑:程序博客网 时间:2024/05/22 08:07

系统蓝屏,很大原因都是系统自身代码有缺陷引起的,而系统代码缺陷很大程度上与内存分配不当有关。由于内存分配不当引起的堆栈溢出、缓冲区溢出等问题,常常会导致系统瘫痪甚至崩溃,所以理解内存分配对于一名合格的程序媛而言非常有必要。

  • 内存分配的形式
  • 内存泄露
  • 缓冲区溢出

内存分配的形式

一个由C/C++编译的程序所占用的系统内存一般分为以下几个部分的内容:


(1)有符号起始的区块(Block Started by Symbol,BSS)段:BSS段通常是指用来存放程序中未初始化的全局数据和静态数据的一块内存区域。BSS段属于静态内存分配,程序结束后静态变量资源由系统自动释放。


(2)数据段(data segment):数据段通常是指用来存放程序中已初始化的全局变量的一块内存区域。数据段也属于静态内存分配。


(3)代码段(code segment/text segment):代码段有时候也叫文本段,通常是指用来存放程序执行代码(暴露类成员函数和全局函数以及其他函数代码)的一块内存区域,这部分区域的大小在程序运行前就已经确定,并且内存区域通常是只读。在代码段中,也有可能包含一些只读的常数变量,如字符串常量。这个段一般是可以被共享的,如在linux系统中打开了两个vi来编辑文本,那么一般来说这两个vi是共享一个代码段的。


(4)堆(heap):堆用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。当进程调用malloc或new等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张),当利用free或delete等函数释放内存时,新分配的内存就被动态添加到堆上(堆被扩张),当利用free或delete等函数释放内存时,被释放内存从堆中被删除(堆被缩减)。堆一般由程序员分配释放,若程序员不释放,程序结束时可能由操作系统回收


(5)栈(stack):栈用户存放程序临时创建的局部变量,一般包括函数括弧中定义的变量(不包括static声明的变量,static意味着在数据段中存放变量)。除此之外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且等到调用结束后,函数的返回值也会被存放回栈中。栈由编译器自动分配释放,存放函数的参数值、局部变量的值等。其操作方式类似于数据结构中的栈。栈内存分配运算内置于处理器的指令集中,一般使用寄存器来存取,效率很高,但是分配的内存容量有限。


注意:代码段和数据段之间有明确的分隔,但是数据段和堆栈段之间没有,而且栈是向下增长的,堆是向上增长的。

内存泄露

堆是动态分配内存的,并且可以分配使用很大的内存,使用不好会产生内存泄露。频繁的使用malloc和free会产生内存碎片(类似于磁盘碎片)。

所谓内存泄露(memory leak)是指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况。一般常说的内存泄露是指堆内存的泄露,内存泄露其实并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,失去了对该段内存的控制,因而造成了内存的浪费。内存泄露与许多其他问题有着相似的症状,并且通常情况下只能由那些可以获得程序源代码的程序媛才可以分析出来

应用程序一般使用malloc、calloc、realloc、new等函数从堆中分配到一块内存,使用完后,程序必须负责相应地调用free或delete释放该内存块,否则这块内存就不能被再次使用,造成内存泄露

内存泄露往往会导致系统出现CPU资源耗尽的严重后果(深受其害啊。。。),所以开发人员在编码过程中需要养成良好的编程习惯,用malloc或new分配的内存都应当在适当的实际用free或delete释放,在对指针赋值前,要确保没有内存位置会变为孤立的。每当释放结构化的元素,而该元素又包含指向动态分配的内存位置的指针时,都应首先遍历自内存位置并从那里开始释放,然后再遍历回父节点,始终正确处理返回动态分配的内存引用的函数返回值

缓冲区溢出

缓冲区是程序运行的时候机器内存中的一个连续块,它保存了给定类型的数据,随着动态分配变量会出现问题。缓冲区溢出是指当向缓冲区内填充数据位数超过了缓冲区自身的容量限制时,发生的溢出的数据覆盖在合法数据(数据、下一条指令的指针、函数返回地址等)上的情况。最好的情况是程序不允许输入超过缓冲区长度的字符并检查数据长度,由于大多数程序都会假设数据长度总是与所分配的储存空间相当,进而存在缓冲区溢出安全隐患。

0 0