1、程序内存的分配

一个由C/C++编译的程序占用的内存分为以下几个部分:
1)栈区(stack) — 由编译器自动分配释放 , 存放为运行函数而分配的局部变量、 函数参数、 返回数据、 返回地址等。 其操作方式类似于数据结构中的栈。
2)堆区(heap) — 一般由程序员分配释放, 若程序员不释放, 程序结束时可能由OS回收,否则程序就会存在内存泄漏的问题 。 分配方式类似于链表。
3)全局区(静态区) (static) —存放全局变量、 静态数据、 常量。 程序结束后由系统释放。
4)文字常量区 —常量字符串就是放在这里的。 程序结束后由系统释放。
5) 程序代码区—存放函数体(类成员函数和全局函数) 的二进制代码

内存分配方式有三种:
1)从静态存储区域分配:内存在程序编译的时候就已经分配好, 这块内存在程序的整个运行期间都存在。 例如全局变量, static变量。
2)在栈上创建:在执行函数时, 函数内局部变量的存储单元都可以在栈上创建, 函数执行结束时这些存储单元自动被释放。 栈内存分配运算内置于处理器的指令集中, 效率很高, 但是分配的内存容量有限。
3)从堆上分配:亦称动态内存分配。程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存期由程序员决定, 使用非常灵活, 但如果在堆上分配了空间, 就有责任回收它, 否则运行的程序会出现内存泄漏。频繁地分配和释放不同大小的堆空间将会产生堆内存碎块。

(new和malloc是C++中的内存分配关键字)

使用动态内存很明显的好处就是:不需要预先分配存储空间且分配的空间可以根据程序的需要扩大或缩小,这样可以有效的使用内存空间。

malloc和free

C函数库中的malloc和free分别用于执行动态内存分配和释放。这两个函数的原型如下所示,他们都在头文件stdlib.h中声明。

void *malloc ( size_t size );

void free ( void *pointer );

malloc的作用是在内存的动态存储区中分配一个长度为size的连续空间。其参数是一个无符号整形数,返回值是一个指向所分配的连续存储域的起始地址的指针。还有一点必须注意的是,当函数未能成功分配存储空间(如内存不足)就会返回一个NULL指针。所以在调用该函数时应该检测返回值是否为NULL,确保非空之后再使用非常重要。malloc所分配的内存是一块连续的空间。同时,malloc实际分配的内存空间可能会比你请求的多一点,但是这个行为只是由编译器定义的。malloc不知道用户所请求的内存需要存储的数据类型,所以malloc返回一个void *的指针,它可以转换为其它任何类型的指针。

由于内存区域总是有限的,不能不限制地分配下去,而且一个程序要尽量节省资源,所以当所分配的内存区域不用时,就要释放它,以便其它的变量或者程序使用。这时我们就要用到free函数。free的参数必须要么是NULL,要么是从malloc、relloc、calloc返回的值。作用是释放之前返回的指针指向的内存空间,向free传递一个NULL参数不会产生任何效果。

calloc和realloc与malloc的区别

calloc和realloc的原型如下:

void *calloc ( size_t num_elements, size_t element_size );

void *realloc (void *ptr, size_t new_size );

calloc和malloc 主要的区别在于前者在返回内存的指针之前将它初始化为0,另外它们请求数量的方式不同。calloc的参数包括所需元素的数量和每个元素的字节,根据这些值可以计算出总共需要分配的内存空间。

realloc函数用于修改一个原先已经分配的内存块的大小,可以使一块内存的扩大或缩小。当起始空间的地址为空,即*ptr = NULL,则同malloc。当*ptr非空:若nuw_size < size,即缩小*ptr所指向的内存空间,该内存块尾部的部分内存被拿掉,剩余部分内存的原先内容依然保留;若nuw_size > size,即扩大*ptr所指向的内存空间,如果原先的内存尾部有足够的扩大空间,则直接在原先的内存块尾部新增内存,如果原先的内存尾部空间不足,或原先的内存块无法改变大小,realloc将重新分配另一块new_size大小的内存,并把原先那块内存的内容复制到新的内存块上。因此,使用realloc后就应该改用realloc返回的新指针。

使用方法程序示例

 int *ptr =NULL;
ptr = (int*)malloc(sizeof(int)*size);
if (*ptr == NULL)
{
strerror(error);
return;
}

上例中动态分配了size个整型存储区域。动态分配内存的步骤可细分为:分配size个整型的连续存储空间,并返回一个指向其起始地址的整型指针把此整型指针地址赋给ptr, 检测返回值是否为NULL。注意,类型转换(int*)将函数返回的地址转换成int类型的指针。这么做是因为malloc()是一般用途的函数,可为任何类型的数据分配内存。sizeof是一个运算符,它返回一个size_t类型的无符号整数,该整数是存储它的参数需要的字节数。它把关键字如int或float等作为参数,返回存储该类型的数据项所需的字节数。它的参数也可以是变量或数组名。把数组名作为参数时,sizeof返回存储整个数组所需的字节数。前一个例子请求分配足以存储size个int数据项的内存。以这种方式使用sizeof,可以根据不同的C编译器为int类型的值自动调整所需的内存空间。

 int *p1,*p2;
p1 = (int*)malloc(size * sizeof(int));
p2=p1;
……
free(p1); /*或者free(p2)*/

给free函数传递其它的值很可能造成死机或其它灾难性的后果。注意:这里重要的是指针的值,而不是用来申请动态内存的指针本身。

malloc返回值赋给p1,又把p1的值赋给p2,所以此时p1,p2都可作为free函数的参数。malloc函数是对存储区域进行分配的。 free函数是释放已经不用的内存区域的。 所以由这两个函数就可以实现对内存区域进行动态分配并进行简单的管理了。

下面是使用动态分配的内存的基本规则:

●避免分配大量的小内存块。分配堆上的内存有一些系统开销,所以分配许多小的内存块比分配几个大内存块的系统开销大。

●仅在需要时分配内存。只要使用完堆上的内存块,就释放它。

●总是确保释放已分配的内存。在编写分配内存的代码时,就要确定在代码的什么地方释放内存。

●在释放内存之前,确保不会无意中覆盖堆上分配的内存的地址,否则程序就会出现内存泄漏。在循环中分配内存时,要特别小心。

C程序的内存分配及动态内存的更多相关文章

  1. Android JNI编程(五)——C语言的静态内存分配、动态内存分配、动态创建数组

    版权声明:本文出自阿钟的博客,转载请注明出处:http://blog.csdn.net/a_zhon/. 目录(?)[+] 一:什么是静态内存什么又是动态内存呢? 静态内存:是指在程序开始运行时由编译 ...

  2. C++_类和动态内存分配1—动态内存和类

    静态类成员 num_strings成员声明为静态存储类.静态类成员有一个特点:无论创建了多少对象,程序都只创建一个静态类变量副本.也就是说,类的所有对象共享一个静态成员.num_strings成员可以 ...

  3. rt-thread中动态内存分配之小内存管理模块方法的一点理解

    @2019-01-18 [小记] rt-thread中动态内存分配之小内存管理模块方法的一点理解 > 内存初始化后的布局示意 lfree指向内存空闲区首地址 /** * @ingroup Sys ...

  4. oracle结构-内存结构与动态内存管理

    内存结构与动态内存管理 内存是影响数据库性能的重要因素. oracle8i使用静态内存管理,即,SGA内是预先在参数中配置好的,数据库启动时就按这些配置来进行内在分配,oracle10g引入了动态内存 ...

  5. (转)java内存分配分析/栈内存、堆内存

    转自(http://blog.csdn.net/qh_java/article/details/9084091) java内存分配分析/栈内存.堆内存 java内存分配分析 本文将由浅入深详细介绍Ja ...

  6. SQL SERVER 内存分配及常见内存问题(2)——DMV查询

    原文:SQL SERVER 内存分配及常见内存问题(2)--DMV查询 内存动态管理视图(DMV): 从sys.dm_os_memory_clerks开始. SELECT [type] , SUM(v ...

  7. SQL SERVER 内存分配及常见内存问题(1)——简介

    原文:SQL SERVER 内存分配及常见内存问题(1)--简介 一.问题: 1.SQL Server 所占用内存数量从启动以后就不断地增加: 首先,作为成熟的产品,内存溢出的机会微乎其微.对此要了解 ...

  8. malloc内存分配与free内存释放的原理

    malloc内存分配与free内存释放的原理 前段时间一直想看malloc的原理,在搜了好几篇malloc源码后遂放弃,晦涩难懂. 后来室友买了本深入理解计算机系统的书,原来上面有讲malloc的原理 ...

  9. 目录_Java内存分配(直接内存、堆内存、Unsafel类、内存映射文件)

    1.Java直接内存与堆内存-MarchOn 2.Java内存映射文件-MarchOn 3.Java Unsafe的使用-MarchOn 简单总结: 1.内存映射文件 读文件时候一般要两次复制:从磁盘 ...

随机推荐

  1. 【转】Python 面向对象(初级篇)

    [转]Python 面向对象(初级篇) 51CTO同步发布地址:http://3060674.blog.51cto.com/3050674/1689163 概述 面向过程:根据业务逻辑从上到下写垒代码 ...

  2. Tomcat安装7.0.91

    版本升级,JDK 1.7,Tomcat从7.0.73升级到7.0.91 为什么升级?解决安全漏洞! 升级就正常流程,下载*.tar.gz ,解压,改配置. 但碰到神奇的坑: 1.server.xml中 ...

  3. fabric.js PatternBrush

    // Original canvas const canvas = new fabric.Canvas('canvas'); fabric.Image.fromURL('https://picsum. ...

  4. ubuntu 精简配置

    是这样的情况,在windows 7的vm虚拟机上装了Ubuntu 12.04 Desktop,主要是想用它的gui, 所以把不要的给删了. sudo apt-get -y --auto-remove ...

  5. ASP.NET MVC5高级编程 之 视图

    1.1理解视图约定 当创建一个项目模版时,可以注意到,项目以一种非常具体的方式包含了一个结构化的Views目录.在每一个控制器的View文件夹中,每一个操作方法都有一个同名的视图文件与其对应.这就提供 ...

  6. [C]va_list可变长参数的使用

    一.概述 运用标准C的头文件stdarg.h提供的宏可以实现函数的自定义传参个数: 二.语法 1.va_list是一个可变长参数类型,在使用可变长参数的函数中可以定义1个或多个va_list类型参数, ...

  7. Redis重大版本

    Redis借鉴了Linux操作系统对于版本号的命名规则: 版本号第二位如果是奇数,则为非稳定版本(例如2.7.2.9.3.1),如果是偶数,则为稳定版本(例如2.6.2.8.3.0.3.2), 当前奇 ...

  8. VUE 多页面配置(一)

    1. 概述 1.1 说明 项目开发过程中会遇到需要多个主页展示情况,故在vue单页面的基础上进行配置多页面开发以满足此需求. 2. 实例 2.1 页面配置 2.1.1 默认首页 使用vue脚手架搭建后 ...

  9. centos6.5安装python2.7、pip、numpy、scipy

    1..安装Development Tools yum groupinstall -y 'development tools' 2.安装SSL.bz2.zlib来为Python的安装做好准备工作 yum ...

  10. est是基于less的样式工具库

    网址:http://ecomfe.github.io/est/ 此处HTML中如果直接引用less就会报错! est 如果直接引用less和js 是会报错的 样式规范:https://www.zybu ...