先举个例子:某用户需要一个将任意多个整数按大小排序的程序。(在计算机文件夹中,当文件很多时经常用到排序)
1。若不用动态分配内存,那就定义一个超大的数组吧!问题是,如果用户不需要那么大,不就浪费了?如果定义的数组还不够大,不就不能满足需求了?
2。如果用动态分配,就解决上述问题了。当你需要多大内存时,就给你多大——如果有的话——这就是动态分配的意义。
现在看上述问题的代码,我调试过的:
----------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
void main()
{
int n,*p,i,j,m;
printf("本程序可对任意个整数排序;\n");
printf("请输入整数的总个数: ");
scanf("%d",&n);
p=(int *)calloc(n,sizeof(int));
if(p==0) {
printf("分配失败!\n");
exit(1);
}
printf("请输入这些整数:\n");
for(i=0;i<n;i++)
scanf("%d",p+i);
for(i=1;i<n;i++)
{
for(j=0;j<n-i;j++)
if(*(p+j)>*(p+j+1))
{
m=*(p+j);
*(p+j)=*(p+j+1);
*(p+j+1)=m;
}
}
printf("将这些整数从小到大排列输出为:");
for(i=0;i<n;i++)
{
if(i%5==0) printf("\n");
printf(" d;",*(p+i));
}
printf("\n");
free(p);
}
----------------------------------------------------------------------
调用calloc函数时,calloc(n,sizeof(int))表示请求n个连续的、每个长度为整型的空间,若成功返回这些空间的首地址。(int *)表示将这个地址放在指针中。到此为止,就可以用指针来对分配到的空间操作了。注意,最后一定要用free函数释放申请到的空间,否则这部分空间会一直占着。
malloc、calloc、realloc的用法(以上述问题为例)及区别:
1。malloc(n*sizeof(int))
2。calloc(n,sizeof(int))
3。realloc(p,sizeof(int)*n)
=====================================================================
一、概述:
二、内存分配方式
在操作系统中,内存分配主要以下面三种方式存在:
(2)栈上的内存分配。栈是系统数据结构,对于进程/线程是唯一的,它的分配与释放由操作系统来维护,不需要开发者来管理。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时,这些存储单元会被自动释放。栈内存分配运算内置于处理器的指令集中,效率很高,不同的操作系统对栈都有一定的限制。
(3) 堆上的内存分配,亦称动态内存分配。程序在运行的期间用malloc申请的内存,这部分内存由程序员自己负责管理,其生存期由开发者决定:在何时分配,分配多少,并在何时用free来释放该内存。这是唯一可以由开发者参与管理的内存。使用的好坏直接决定系统的性能和稳定。
三、动态内存分配概述
四、动态内存分配的实现
4.1、动态内存管理的一般机制:
4.2、Linux下动态内存分配的实现:
注意:这里我们讨论的都是虚拟内存的分配(即应用层面上的内存分配),主要由glibc来实现,它与内核中实际物理内存的分配是不同的层面,进程所分配到的虚拟内存可能没有对应的物理内存。如果所分配的虚拟内存没有对应的物理内存时,操作系统会利用缺页机制来为进程分配实际的物理内存。
4.3、Uc/OS 下内存分配的实现:
(1)、创建内存分区:在使用内存之前,开发者必须首先调用OSMemCreare()函数来创建相应的内存分区,在创建内存分区成功后,就会在系统中存在一个以开发者指定内存大小,指定内存块数目的内存池。在此过程中,开发者需要明确的知道系统的内存分布,并指明内存池的基址。
(2)、申请内存:当系统内存分区创建好了后,系统就可以从相应的内存分区中获取内存了。在Uc/OS 中,主要利用OSMemGet()来申请内存,应用程序会根据所需要内存的大小,从开发者指定的内存池中申请内存。
(3)、释放内存:因为内存是系统的紧缺资源,当应用不再需要使用所申请的内存时,应该及时释放该内存。在Uc/OS 中,主要利用OSMemPut()来释放不再需要的内存,在此过程中,开发者应该保证把该内存释放回原内存的分区。
五、小结:
在本文简单解析了两种动态内存管理实现,它们互有忧缺点:对于以虚拟内存机制和分页机制为基础的动态内存管理(如Linux等),由于请求分页机制的存在,不能满足系统实时性方面的要求,但是它能为应用提供最多能到4G的内存空间,而且由于应用虚拟内存机制,可以为进程空间提供保护,一个进程的崩溃不会影响其他的进程。对于基于非虚拟内存管理机制的系统,由于可以直接操作物理内存,提高了系统实时性,在这样的系统中,开发者的参与度比基于虚拟内存机制的要高。其缺点是没有进程间的保护机制,一个进程或任务的错误很容易导致整个系统的崩溃。
参考:
1、Glibc 源代码
2、嵌入式实时操作系统Uc/OS-II
3、经典收藏之 - C++内存管理详解:http://www.oneedu.cn/xxyd/jzjs/aspnet/200703/14963.html
4、Understanding Linux kernel
5、The Virtual-Memory Manager in Windows NT:
http://msdn2.microsoft.com/en-us/library/ms810616.aspx
============================================================================
堆是硬件实现的,栈是一种数据结构,但是很多情况已经不区分它们了
栈是由cpu实现的一种数据结构,其特点是后进先出。用于程序局部变量、程序返回地址。调用子程序、声明局部变量时,实际上就是在告诉编译程序使用“栈”这种数据结构。程序链接(link.exe)时,必须告诉链接程序为进程保留多大的栈空间。进程被加载时,操作系统就为该进程分配或者说保留这么大的内存空间作为栈来使用。
代码空间、栈空间、全局变量空间都是保留的,没有这些空间进程会加载失败。这个时候操作系统会提示系统内存太少无法加载进程。
堆空间相对代码空间、栈空间、全局变量空间,它是没娘的孩子。因为系统除去这些保留的空间,剩下的都是自由空间,它的头上插了根草标,表示这些空间没有使用,谁都可以自由的使用。
堆空间唯一有用的时候,就是你的程序在执行malloc、realloc、new等操作时,堆空间就像站街女等待你的挑选。不过,操作系统的眼光好一点,它会通过malloc等函数帮你选好合适的站街女,选好的站街女就是这几个函数的返回值。
站街女用完了之后,就用free、delete等操作撵走。
而堆是,进程加载之后,系统多余的空间。
如果程序加载时,操作系统提示内存不够导致加载失败,则必须去电脑城买一条更大的内存。
如果程序运行过程中,提示栈溢出,则必须告诉程序员,重新链接程序。链接程序时指定大一点的栈空间。
如果程序运行过程中,提示内存不够,这意味着堆空间不够。也必须去电脑城买一条更大的内存。
如果不想买内存,或许可以这样:关闭一些已经运行的程序。比如防火墙、杀毒软件等,游戏、realplay、winamp就别关了。电脑不娱乐,还有什么用呀^_^。
而代码空间和全局变量空间不一样,程序编译好了就知道需要多大的代码空间和全局变量空间。所以链接程序可以自己决定。