一、内存介绍

本文主要介绍C内存管理基本概念,以及C语言编译后的可执行程序的存储结构和执行结构。


在用户存储空间,一个C程序的在内存中的分配分类5大部分:代码段、全局已初始化数据段、bss段、堆和栈。

当中各部分详细所指:

    1、代码段(text segment)
   存放CPU运行的机器指令(machine instructions)。代码区一般是仅仅读的,使其仅仅读的原因是防止程序意外地改动了它的指令。

    2、全局已初始化数据段    存入的是初始化的全局变量、静态变量(包含全局静态变量和局部静态变量)和常量数据(如字符串常量)。

    3、bss段 / 全局未初始化数据区
   存入的是全局未初始化变量。BSS这个叫法是依据一个早期的汇编运算符而来。这个汇编运算符标志着一个块的開始。BSS区的数据在程序開始运行之前被内核初始化为0或者空指针(NULL)。
    4、堆 heap
  用于动态内存分配。堆在内存中位于bss区和栈区之间。一般由程序猿分配和释放,若程序猿不释放。程序结束时有可能由OS回收。
    5、栈 stack
  由编译器自己主动分配释放,存放函数的參数值、局部变量的值等。

其操作方式类似于数据结构中的栈。


之所以分成这么多个区域,主要基于下面考虑:

一个进程在运行过程中。代码是依据流程依次运行的。仅仅须要訪问一次。当然跳转和递归有可能使代码运行多次,而数据一般都须要訪问多次,因此单独开辟空间以方便訪问和节约空间。

暂时数据及须要再次使用的代码在执行时放入栈区中,生命周期短。

全局数据和静态数据有可能在整个程序运行过程中都须要訪问。因此单独存储管理。

堆区由用户自由分配,以便管理。


样例:
    

二、内存分配方式
    在C语言中。对象能够使用静态或动态的方式分配内存空间。

静态分配:编译器在处理程序源码时分配。

动态分配:程序在运行时调用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--更改已经配置的内存空间
    realloc()函数用来从堆上分配内存,当须要扩大一块内存空间时,realloc()试图直接从堆上当前内存段后面的字节中获得很多其它的内存空间,假设可以满足。则返回原指针;假设当前内存段后面的空暇字节不够,那么就使用堆上第一个可以满足这一要求的内存块。将眼下的数据拷贝到新的位置,而将原来的数据块释放掉。假设内存不足,又一次申请空间失败,则返回NULL。

此函数定义例如以下:

void *realloc(void *ptr,size_t size)

參数ptr为先前由malloc、calloc和realloc所返回的内存指针,而參数size为新配置的内存大小

    当调用realloc()函数又一次分配内存时,假设申请失败。将返回NULL,此时原来指针仍然有效,因此在程序编写时须要进行推断,假设调用成功。realloc()函数会又一次分配一块新内存,并将原来的数据复制到新位置,返回新内存的指针,而释放掉原来指针(realloc()函数的參数指针)指向的空间。原来的指针变为不可用(即不须要再释放,也不能再释放),因此,一般不使用下面语句:
ptr=realloc(ptr,new_amount)

假设内存降低。malloc只改变索引信息。但并不代表被降低的部分还能够訪问。这一部分内存将交给系统内存分配子程序。

  • 其它内存管理函数calloc和alloca
calloc是malloc函数的简单包装,它的主要长处是把动态分配的内存进行初始化,所有清零。其操作及语法类似malloc()函数。

alloca()函数用来在栈中分配size个字节的内存空间。因此函数返回时会自己主动释放掉空间。alloca函数定义及库头文件例如以下:

返回值:若分配成功返回指针。失败则返回NULL。

它与malloc()函数的差别主要在于:

alloca是向栈申请内存。无需释放。malloc申请的内存位于堆中,终于须要函数free来释放。

malloc函数并没有初始化申请的内存空间。因此调用malloc()函数之后,还需调用函数memset初始化这部分内存空间;alloca则将初始化这部分内存空间为0。

输出为:

C 这些东西的内存管理的更多相关文章

  1. Swift中的可选链与内存管理(干货系列)

    干货之前:补充一下可选链(optional chain) class A { var p: B? } class B { var p: C? } class C { func cm() -> S ...

  2. C++ 系列:内存管理

    1.内存分配方式 内存分配方式有三种: (1)从静态存储区域分配. 内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在.例如全局变量,static变量. (2)在栈上创建. 在执行函 ...

  3. Linux内核笔记--内存管理之用户态进程内存分配

    内核版本:linux-2.6.11 Linux在加载一个可执行程序的时候做了种种复杂的工作,内存分配是其中非常重要的一环,作为一个linux程序员必然会想要知道这个过程到底是怎么样的,内核源码会告诉你 ...

  4. ARC内存管理机制详解

    ARC在OC里面个人感觉又是一个高大上的牛词,在前面Objective-C中的内存管理部分提到了ARC内存管理机制,ARC是Automatic Reference Counting---自动引用计数. ...

  5. objective-c 语法快速过(6)内存管理原理

    内存管理基本原理(最重要) 移动设备的内存极其有限(iphone 4内存512M),每个app所能占用的内存是有限制的(几十兆而已). 当app所占用的内存较多时,系统会发出内存警告,这时得回收一些不 ...

  6. C#内存管理与垃圾回收

    垃圾回收还得从根说起,就像生儿育女一样. 根:根是一个位置,存放一个指针,该指针指向托管堆中的一个对象,或是一个空指针不指向任何对象,即为null.根存在线程栈或托管堆中,大部分的跟都在线程栈上,因为 ...

  7. 黑马程序员_ Objective-c 内存管理笔记

    引用计数器 当一个对象被创建出来,就要分配给内存这个对象,当不用这个对象的时候,就要及时的回收,为了可以明确知道对象有没有被使用,就要用引用计数器来体现,只要计数器不为0,表明对象被使用中. 1.方法 ...

  8. [转]全面理解Unity加载和内存管理

    [转]全面理解Unity加载和内存管理 最近一直在和这些内容纠缠,把心得和大家共享一下: Unity里有两种动态加载机制:一是Resources.Load,一是通过AssetBundle,其实两者本质 ...

  9. 【Bugly干货分享】iOS内存管理:从MRC到ARC实践

    Bugly 技术干货系列内容主要涉及移动开发方向,是由Bugly邀请腾讯内部各位技术大咖,通过日常工作经验的总结以及感悟撰写而成,内容均属原创,转载请标明出处. 对于iOS程序员来说,内存管理是入门的 ...

随机推荐

  1. 如何自动以管理员身份运行.NET程序?

    原文:如何自动以管理员身份运行.NET程序? windows 7和vista提高的系统的安全性,同时需要明确指定“以管理员身份运行”才可赋予被运行软件比较高级的权限,比如访问注册表等.否则,当以普通身 ...

  2. 用golang写的生成文件md5sum,检验文件md5sum

    源代码地址: https://github.com/sndnvaps/md5sum-golang

  3. java.io.FileNotFoundException: /home/hadoop/hadoop/dfs/namenode/current/VERSION (Permission denied)

    今天布置hadoop集群,尝试单独将secondarynamenode分属到一台独立的虚拟机上, 当格式化后,start-dfs.sh.namenode没启动.查看日志.报错例如以下 查看权限才发现, ...

  4. 桥模式设计模式进入Bridge

    Abstraction:抽象部分的父类,定义须要实现的接口. 维护对实现部分的引用,从而把实现桥接到Implementor中去 Implementor:实现部分的接口 RefinedAbstracti ...

  5. openGL研究钞四 : 关于颜色, 尺寸, 虚线, 多边形逆转, 空洞, 使用位图

    转载请保留源,,,,hushuai1992http://blog.csdn.net/u013642494/article/category/2675731 额. 这个标题我都不知道该怎么起了. 假设没 ...

  6. 使用dfs实现1至n全阵列

    使用dfs实现1至n全阵列. 我的方法是从所述第一位置开始,使用dfs看上去就像每个头号位置, 当某个位置.从小到大枚举1至n所有号码,打假说 尚未使用之前在这个位置上的几个选择这个号码.然后搜索下 ...

  7. sharepoint 2013 个人网站公共母板页路径地址

    C:\Program Files\Common Files\microsoft shared\Web Server Extensions\15\TEMPLATE\FEATURES\MySiteUnif ...

  8. [Unity3D]Unity3D游戏开发《反对》说到游戏(上)——目标跟踪

    朋友,大家好.我是秦培,欢迎关注我的博客.我的博客地址blog.csdn.net/qinyuanpei. 首先博主要自我反省,过了这么久才来更新博客,这段时间主要是在忙着写期末的作业,所以博主基本上没 ...

  9. vs2015基于VisualStudioOnline协同工作流程

    项目负责人登陆自己的vsonline新建项目就不多说了. 直接从邀请队友开始 项目负责人操作 被邀请的邮箱务必是可以登录visualstudio的邮箱 发送邀请后,被邀请人登陆自己的邮箱,查看邀请人发 ...

  10. 完美世界3D格斗手游[格斗宝贝]今日公測

    狗刨学习网报道 / 经过近两年井喷式的发展,国内手游市场洗牌的信号愈加强烈.用户体验的提升.以及对产品核心品质的要求.促进了手游的精品化.而白热化的市场竞争,也催生了各大厂商在细分市场的抢滩.当中.更 ...