C\C++内存区域划分比较

内存定义

硬件角度:内存是计算机必不可少的一个组成部分,是于CPU沟通的桥梁,计算机中所有的程序都是运行在内存中的。
逻辑角度:内存是一块具备随机访问能力,支持读、写操作,用来存放程序及程序运行中产生的数据的区域。

内存单位和编址

  • 位 :( bit ) 是电子计算机中最小的数据单位。每一位的状态只能是0或1。

  • 字节:1 Byte = 8 bit ,是内存基本的计量单位,

  • 字:“字” 由若干个字节构成,字的位数叫做字长,不同档次的机器有不同的字长。

  • KB :1KB = 1024 Byte。也就是1024个字节。

  • MB : 1MB = 1024 KB。类似的还有GB、TB。

  • 内存编址:计算机中的内存按字节编址,每个地址的存储单元可以存放一个字节(8个bit)的数据,CPU通过内存地址获取指令和数据,并不关心这个地址所代表的空间具体在什么位置、怎么分布,因为硬件的设计保证一个地址对应着一个固定的空间,所以说:内存地址和地址指向的空间共同构成了一个内存单元。

  • 内存地址:内存地址通常用十六进制的数据表示,例如通常在C或者Objective-C中输出一个变量的地址可能为:0x7fff5fbff79c,这就是一个用十六进制的数表示的地址。

C内存区域划分

区域 功能
栈区 局部变量,函数参数
堆区 动态内存分配,由malloc()/calloc()/realloc()分配
BSS段 未初始化全局变量,未初始化全局静态变量
全局区(静态区) 已初始化全局变量和静态变量
常量区 字符串常量,以及const修饰的全局变量
代码区 可执行代码

由高地址到低地址依次为:

  1. 栈区
    1)程序运行时由编译器自动分配的一块连续的内容,栈作为内存中存储结构,通常存放程序临时创建的局部变量,即函数括大括号 “{ }” 中定义的变量,其中还包括函数调用时其形参,调用后的返回值等。 栈是由到高地址向低地址扩展的数据结构
    2)程序结束时由编译器自动释放,空间是循环利用自动管理的,一般不需要人为操作
    3)栈由系统自动分配,程序员无法控制
    4)只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出,进而导致意想不到的后果。
    5)存取方式,先进后出
  2. 堆区
    1)通常存放程序运行中动态分配的存储空间,一般由程序员分配释放。堆是低地址向高地址扩展的数据结构,是一块不连续的内存区域,具有“大内存、手工分配管理、申请大小随意、可能会泄露”的特点。
    2)首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序
    3)如果程序员在使用完申请后的堆内存却没有及时把它释放掉,那么这块内存就丢失了(进程自身认为该内存没被使用,但是在堆内存记录中该内存仍然属于这个进程,所以当需要分配空间时又会重新去申请新的内存而不是重复利用这块内存),就是我们常说的-内存泄漏,所以内存泄漏指的是堆内存被泄露了。程序结束时可能会由操作系统回收,也许就一直占用着直至关机。
  3. BSS段
    Block Started by Symbol的简称,通常是指用来存放程序中未初始化的全局变量和静态变量,该区域会在main函数执行前进行自动清零。BSS段属于静态内存分配。
  4. 全局区
    1)存放程序中已初始化的全局变量和静态变量,编译器编译时分配内存。初始化的全局变量和静态变量和未初始化的放在相邻的两个区域,全局变量和静态变量的存储是放在同一块区域的。
    2)将变量定义的类型前加static,则该变量存储在静态存储区
    3)由于全局变量一直占据内存空间且不易维护,推荐少用,程序结束时释放。 static: 只初始化一次,只有程序退出才释放(将变量写成static可加快速度)
  5. 常量区
    1)常量占用内存,只读状态,决不可修改
    2)常量字符串就是放在这里的,程序结束后由系统释放
  6. 代码区
    通常是指用来存放程序执行代码的一块内存区域,并且内存区域通常属于只读, 某些架构也允许代码段为可写。这部分区域的大小在程序运行前就已经确定,所有的语句编译后会生成CPU指令存储在代码区。

C++内存区域划分

区域 功能
栈区 局部变量,函数参数
堆区 动态内存分配,由new申请
自由存储区 malloc()/calloc()/realloc()分配空间,由free()释放
全局区(静态区) 全局变量和静态变量
常量区 字符串常量,以及const修饰的全局变量
代码区 可执行代码

C/C++内存区域区别

在C中由程序员用malloc()/calloc()/realloc()分配空间,free()释放所申请的空间。在C++中由new申请内存,由delete释放申请的内存。
C++多了一个自由存储区,和C中的堆机制对应,由程序员用malloc()/calloc()/realloc()分配空间,由free()释放。如果程序员忘记free()了,则会造成内存泄漏,程序结束时可能会有操作系统回收。
在C++中,由于编译器会给全局变量和静态变量自动初始化赋值,所以没有区分初始化和未初始化变量。C语言中,对全局区/静态区中变量初始化与未初始化是放在不同区域的。

堆和栈的对比

栈空间分静态分配和动态分配两种。静态分配是编译器完成的,比如自动变量(auto)的分配。动态分配由alloca函数完成。栈的动态分配无需释放(是自动的),也就没有释放函数。为可移植的程序起见,栈的动态分配操作是不被鼓励的!堆空间的分配总是动态的,虽然程序结束时所有的数据空间都会被释放回系统,但是精确的申请内存/ 释放内存匹配是良好程序的基本要素。

碎片问题:对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈来讲,则不会存在这个问题,因为栈是先进后出的队列,永远都不可能有一个内存块从栈中间弹出,在他弹出之前,在他上面的后进的栈内容已经被弹出。
生长方向:对于堆来讲,生长方向是向上的,也就是向着内存地址增加的方向;对于栈来讲,它的生长方向是向下的,是向着内存地址减小的方向增长。
分配方式:堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的,他的动态分配是由编译器进行释放,无需我们手工实现。
分配效率:栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是C/C++函数库提供的,它的机制是很复杂的,例如为了分配一块内存,库函数会按照一定的算法在堆内存中搜索可用的足够大小的空间,如果没有足够大小的空间(可能是由于内存碎片太多),就有可能调用系统功能去增加程序数据段的内存空间,这样就有机会分到足够大小的内存,然后进行返回。显然,堆的效率比栈要低得多。

你可能感兴趣的:(C/C++内存,C/C++内存)