A. linux系统下的c语言中的虚拟内存分配问题
因为内存管理由glibc管理,当它认为需要释放时,才释放前提是,你已经让它释放了,说的简单就是,你让它释放,它要过一段时间等合适了,再释放
B. 怎么用codeblocks编写c语言的图形程序
在codeblocks中,可以通过集成EGE库,来实现C语言图形程序的编写,具体方式如下:
一、安装:
1、下载ege安装包;
2、将安装包解压;
3、把压缩包里include目录下所有文件,复制到编译器安装目录下的include目录内,例如D:MinGWinclude;
4、把lib目录下对应编译器名目录下的文件,复制到编译器安装目录下的lib目录内,例如D:MinGWlib。
二、建立工程:
只要第1步做好以后,其实已经安装好ege了,剩下的只是配置build option.
点击file-new-projects,选择Console application:
C. C语言函数的操作函数
所在函数库为string.h、mem.h
mem…操作存贮数组
void *memccpy(void *destin,void *source,unsigned char ch,unsigned n)
void *memchr(void *s,char ch,unsigned n)
void *memcmp(void *s1,void *s2,unsigned n)
int memicmp(void *s1,void *s2,unsigned n)
void *memmove(void *destin,void *source,unsigned n)
void *memcpy(void *destin,void *source,unsigned n)
void *memset(void *s,char ch,unsigned n)
这些函数,mem…系列的所有成员均操作存贮数组.在所有这些函数中,数组是n字节长.
memcpy从source复制一个n字节的块到destin.如果源块和目标块重叠,则选择复制方向,
以例正确地复制覆盖的字节.
memmove与memcpy相同.
memset将s的所有字节置于字节ch中.s数组的长度由n给出.
memcmp比较正好是n字节长的两个字符串s1和s2.些函数按无符号字符比较字节,因此,
memcmp(0xFF,x7F,1)返回值大于0.
memicmp比较s1和s2的前n个字节,不管字符大写或小写.
memccpy从source复制字节到destin.复制一结束就发生下列任一情况:
(1)字符ch首选复制到destin.
(2)n个字节已复制到destin.
memchr对字符ch检索s数组的前n个字节.
返回值:memmove和memcpy返回destin
memset返回s的值
memcmp和memicmp─┬─若s1<s2返回值小于0
├─若s1=s2返回值等于0
└─若s1>s2返回值大于0
memccpy若复制了ch,则返回直接跟随ch的在destin中的字节的一个指针;
否则返回NULL
memchr返回在s中首先出现ch的一个指针;如果在s数组中不出现ch,就返回NULL.
void movedata(int segsrc,int offsrc,
int segdest,int offdest,
unsigned numbytes)
本函数将源地址(segsrc:offsrc)处的numbytes个字节
复制到目标地址(segdest:offdest)
void movemem(void *source,void *destin,unsigned len)
本函数从source处复制一块长len字节的数据到destin.若源地址和目标地址字符串
重叠,则选择复制方向,以便正确的复制数据.
void setmem(void *addr,int len,char value)
本函数把addr所指的块的第一个字节置于字节value中.
str…字符串操作函数
char stpcpy(char *dest,const char *src)
将字符串src复制到dest
char strcat(char *dest,const char *src)
将字符串src添加到dest末尾
char strchr(const char *s,int c)
检索并返回字符c在字符串s中第一次出现的位置
int strcmp(const char *s1,const char *s2)
比较字符串s1与s2的大小,并返回s1-s2
char strcpy(char *dest,const char *src)
将字符串src复制到dest
size_t strcspn(const char *s1,const char *s2)
扫描s1,返回在s1中有,在s2中也有的字符个数
char strp(const char *s)
将字符串s复制到最近建立的单元
int stricmp(const char *s1,const char *s2)
比较字符串s1和s2,并返回s1-s2
size_t strlen(const char *s)
返回字符串s的长度
char strlwr(char *s)
将字符串s中的大写字母全部转换成小写字母,并返回转换后的字符串
char strncat(char *dest,const char *src,size_t maxlen)
将字符串src中最多maxlen个字符复制到字符串dest中
int strncmp(const char *s1,const char *s2,size_t maxlen)
比较字符串s1与s2中的前maxlen个字符
char strncpy(char *dest,const char *src,size_t maxlen)
复制src中的前maxlen个字符到dest中
int strnicmp(const char *s1,const char *s2,size_t maxlen)
比较字符串s1与s2中的前maxlen个字符
char strnset(char *s,int ch,size_t n)
将字符串s的前n个字符置于ch中
char strpbrk(const char *s1,const char *s2)
扫描字符串s1,并返回在s1和s2中均有的字符个数
char strrchr(const char *s,int c)
扫描最后出现一个给定字符c的一个字符串s
char strrev(char *s)
将字符串s中的字符全部颠倒顺序重新排列,并返回排列后的字符串
char strset(char *s,int ch)
将一个字符串s中的所有字符置于一个给定的字符ch
size_t strspn(const char *s1,const char *s2)
扫描字符串s1,并返回在s1和s2中均有的字符个数
char strstr(const char *s1,const char *s2)
扫描字符串s2,并返回第一次出现s1的位置
char strtok(char *s1,const char *s2)
检索字符串s1,该字符串s1是由字符串s2中定义的定界符所分隔
char strupr(char *s)
将字符串s中的小写字母全部转换成大写字母,并返回转换后的字符串
存贮分配子程序,所在函数库为dos.h、alloc.h、malloc.h、stdlib.h、process.h
int allocmem(unsigned size,unsigned *seg)利用DOS分配空闲的内存,
size为分配内存大小,seg为分配后的内存指针
int freemem(unsigned seg)释放先前由allocmem分配的内存,seg为指定的内存指针
int setblock(int seg,int newsize)本函数用来修改所分配的内存长度,
seg为已分配内存的内存指针,newsize为新的长度
int brk(void *endds)
本函数用来改变分配给调用程序的数据段的空间数量,新的空间结束地址为endds
char *sbrk(int incr)
本函数用来增加分配给调用程序的数据段的空间数量,增加incr个字节的空间
unsigned long coreleft() 本函数返回未用的存储区的长度,以字节为单位
void *calloc(unsigned nelem,unsigned elsize)分配nelem个长度为elsize的内存空间
并返回所分配内存的指针
void *malloc(unsigned size)分配size个字节的内存空间,并返回所分配内存的指针
void free(void *ptr)释放先前所分配的内存,所要释放的内存的指针为ptr
void *realloc(void *ptr,unsigned newsize)改变已分配内存的大小,ptr为已分配有内
存区域的指针,newsize为新的长度,返回分配好的内存指针.
long farcoreleft() 本函数返回远堆中未用的存储区的长度,以字节为单位
void far *farcalloc(unsigned long units,unsigned long unitsz)
从远堆分配units个长度为unitsz的内存空间,并返回所分配内存的指针
void *farmalloc(unsigned long size)分配size个字节的内存空间,
并返回分配的内存指针
void farfree(void far *block)释放先前从远堆分配的内存空间,
所要释放的远堆内存的指针为block
void far *farrealloc(void far *block,unsigned long newsize)改变已分配的远堆内
存的大小,block为已分配有内存区域的指针,newzie为新的长度,返回分配好
的内存指针
D. 在windows下用C语言如何实现socket网络编程,需要用到哪些头文件或者库
需要用到的头文件包含:
#include <winsock2.h>
#include <windows.h>
与Linux环境下socket编程相比,windows环境多了一个步骤:启动或者初始化winsock库
Winsock,一种标准API,一种网络编程接口,用于两个或多个应用程序(或进程)之间通过网络进行数据通信。具有两个版本:
Winsock 1:
Windows CE平台支持。
头文件:WinSock.h
库:wsock32.lib
Winsock 2:
部分平台如Windows CE貌似不支持。通过前缀WSA可以区别于Winsock 1版本。个别函数如WSAStartup、WSACleanup、WSARecvEx、WSAGetLastError都属于Winsock 1.1规范的函数;
头文件:WinSock2.h
库:ws2_32.lib
mswsock.h用于编程扩展,使用时必须链接mswsock.dll
(4)sbrk的C语言实现扩展阅读
winsock库的加载与卸载:
加载:int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData);
加载成功,返回值为0。
WORD wVersionRequested:加载的winsock版本,使用宏MAKEWORD(x, y),x表示高字节,y表示低字节。然而使用时MAKEWORD(2, 2)。高字节与低字节相同~~
LPWSADATA lpWSAData:WSADATA结构的指针,传入参数后,系统帮助我们填充版本信息。有兴趣的可以看看结构体内容,不过基本用不着。
卸载:int WSACleanup(void);比起加载,卸载的函数真是轻松愉快。
E. C语言中分配内存的函数是怎么写的
Windows下的 malloc 原理就是调用 windows API 的各种内存管理函数申请内存并记录内存状态以便将来释放。
DOS下的 malloc 原理就是调用申请内存的中断申请内存并记录内存状态以便将来释放。
UNIX 和 Linux 都有内存管理的系统调用,malloc 相当于给这些系统调用穿了一件
malloc()工作机制
malloc函数的实质体现在,它有一个将可用的内存块连接为一个长长的列表的所谓空闲链表。调用malloc函数时,它沿连接表寻找一个大到足以满足用户请求所需要的内存块。然后,将该内存块一分为二(一块的大小与用户请求的大小相等,另一块的大小就是剩下的字节)。接下来,将分配给用户的那块内存传给用户,并将剩下的那块(如果有的话)返回到连接表上。调用free函数时,它将用户释放的内存块连接到空闲链上。到最后,空闲链会被切成很多的小内存片段,如果这时用户申请一个大的内存片段,那么空闲链上可能没有可以满足用户要求的片段了。于是,malloc函数请求延时,并开始在空闲链上翻箱倒柜地检查各内存片段,对它们进行整理,将相邻的小空闲块合并成较大的内存块。
malloc()在操作系统中的实现
在 C 程序中,多次使用malloc () 和 free()。不过,您可能没有用一些时间去思考它们在您的操作系统中是如何实现的。本节将向您展示 malloc 和 free 的一个最简化实现的代码,来帮助说明管理内存时都涉及到了哪些事情。
在大部分操作系统中,内存分配由以下两个简单的函数来处理:
void *malloc (long numbytes):该函数负责分配 numbytes 大小的内存,并返回指向第一个字节的指针。
void free(void *firstbyte):如果给定一个由先前的 malloc 返回的指针,那么该函数会将分配的空间归还给进程的“空闲空间”。
malloc_init 将是初始化内存分配程序的函数。它要完成以下三件事:将分配程序标识为已经初始化,找到系统中最后一个有效内存地址,然后建立起指向我们管理的内存的指针。这三个变量都是全局变量:
//清单 1. 我们的简单分配程序的全局变量
int has_initialized = 0;
void *managed_memory_start;
void *last_valid_address;
如前所述,被映射的内存的边界(最后一个有效地址)常被称为系统中断点或者 当前中断点。在很多 UNIX? 系统中,为了指出当前系统中断点,必须使用 sbrk(0) 函数。 sbrk 根据参数中给出的字节数移动当前系统中断点,然后返回新的系统中断点。使用参数 0 只是返回当前中断点。这里是我们的 malloc 初始化代码,它将找到当前中断点并初始化我们的变量:
清单 2. 分配程序初始化函数
#include
void malloc_init()
{
last_valid_address = sbrk(0);
managed_memory_start = last_valid_address;
has_initialized = 1;
}
现在,为了完全地管理内存,我们需要能够追踪要分配和回收哪些内存。在对内存块进行了 free 调用之后,我们需要做的是诸如将它们标记为未被使用的等事情,并且,在调用 malloc 时,我们要能够定位未被使用的内存块。因此, malloc 返回的每块内存的起始处首先要有这个结构:
//清单 3. 内存控制块结构定义
struct mem_control_block {
int is_available;
int size;
};
现在,您可能会认为当程序调用 malloc 时这会引发问题 —— 它们如何知道这个结构?答案是它们不必知道;在返回指针之前,我们会将其移动到这个结构之后,把它隐藏起来。这使得返回的指针指向没有用于任何其他用途的内存。那样,从调用程序的角度来看,它们所得到的全部是空闲的、开放的内存。然后,当通过 free() 将该指针传递回来时,我们只需要倒退几个内存字节就可以再次找到这个结构。
在讨论分配内存之前,我们将先讨论释放,因为它更简单。为了释放内存,我们必须要做的惟一一件事情就是,获得我们给出的指针,回退 sizeof(struct mem_control_block) 个字节,并将其标记为可用的。这里是对应的代码:
清单 4. 解除分配函数
void free(void *firstbyte) {
struct mem_control_block *mcb;
mcb = firstbyte - sizeof(struct mem_control_block);
mcb->is_available = 1;
return;
}
如您所见,在这个分配程序中,内存的释放使用了一个非常简单的机制,在固定时间内完成内存释放。分配内存稍微困难一些。我们主要使用连接的指针遍历内存来寻找开放的内存块。这里是代码:
//清单 6. 主分配程序
void *malloc(long numbytes) {
void *current_location;
struct mem_control_block *current_location_mcb;
void *memory_location;
if(! has_initialized) {
malloc_init();
}
numbytes = numbytes + sizeof(struct mem_control_block);
memory_location = 0;
current_location = managed_memory_start;
while(current_location != last_valid_address)
{
current_location_mcb =
(struct mem_control_block *)current_location;
if(current_location_mcb->is_available)
{
if(current_location_mcb->size >= numbytes)
{
current_location_mcb->is_available = 0;
memory_location = current_location;
break;
}
}
current_location = current_location +
current_location_mcb->size;
}
if(! memory_location)
{
sbrk(numbytes);
memory_location = last_valid_address;
last_valid_address = last_valid_address + numbytes;
current_location_mcb = memory_location;
current_location_mcb->is_available = 0;
current_location_mcb->size = numbytes;
}
memory_location = memory_location + sizeof(struct mem_control_block);
return memory_location;
}
这就是我们的内存管理器。现在,我们只需要构建它,并在程序中使用它即可.多次调用malloc()后空闲内存被切成很多的小内存片段,这就使得用户在申请内存使用时,由于找不到足够大的内存空间,malloc()需要进行内存整理,使得函数的性能越来越低。聪明的程序员通过总是分配大小为2的幂的内存块,而最大限度地降低潜在的malloc性能丧失。也就是说,所分配的内存块大小为4字节、8字节、16字节、 18446744073709551616字节,等等。这样做最大限度地减少了进入空闲链的怪异片段(各种尺寸的小片段都有)的数量。尽管看起来这好像浪费了空间,但也容易看出浪费的空间永远不会超过50%。
F. alloc方法和myalloc方法的区别
malloc()与 alloc()
C语言跟内存分配方式
(1) 从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量。
(2) 在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
(3)从堆上分配,亦称动态内存分配。程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存期由我们决定,使用非常灵活,但问题也最多
C语言跟内存申请相关的函数主要有 alloca,calloc,malloc,free,realloc,sbrk等.其中alloca是向栈申请内存,因此无需释放. malloc分配的内存是位于堆中的,并且没有
初始化内存的内容,因此基本上malloc之后,调用函数memset来初始化这部分的内存空间. calloc则将初始化这部分的内存,设置为0. 而realloc则对malloc申请的内存进行大小的调整.申请的内存最终需要通过函数free来释放. 而sbrk则是增加数据段的大小;
malloc/calloc/free基本上都是C函数库实现的,跟OS无关.C函数库内部通过一定的结构来保存当前有多少可用内存.如果程序malloc的大小超出了库里所留存的空间,那么
将首先调用brk系统调用来增加可用空间,然后再分配空间.free时,释放的内存并不立即返回给os,而是保留在内部结构中. 可以打个比方: brk类似于批发,一次性的向OS申请大的内存,而malloc等函数则类似于零售,满足程序运行时的要求.这套机制类似于缓冲.使用这套机制的原因: 系统调用不能支持任意大小的内存分配(有的系统调用只支持固定大小以及其倍数的内存申请,这样的话,对于小内存的分配会造成浪费; 系统调用申请内存代价昂贵,涉及到用户态和核心态的转换.
函数malloc()和calloc()都可以用来分配动态内存空间,但两者稍有区别。
malloc()函数有一个参数,即要分配的内存空间的大小:
Void *malloc(size_t size);
calloc()函数有两个参数,分别为元素的数目和每个元素的大小,这两个参数的乘积就是要分配的内存空间的大小:
void *calloc(size_t numElements,size_t sizeOfElement);
如果调用成功,函数malloc()和calloc()都将返回所分配的内存空间的首地址。
malloc() 函数和calloc ()函数的主要区别是前者不能初始化所分配的内存空间,而后者能。如果由malloc()函数分配的内存空间原来没有被使用过,则其中的每一位可能都是 0;反之,如果这部分内存空间曾经被分配、释放和重新分配,则其中可能遗留各种各样的数据。也就是说,使用malloc()函数的程序开始时(内存空间还 没有被重新分配)能正常运行,但经过一段时间后(内存空间已被重新分配)可能会出现问题。
calloc() 函数会将所分配的内存空间中的每一位都初始化为零,也就是说,如果你是为字符类型或整数类型的元素分配内存,那么这些元素将保证会被初始化为零;如果你是为指针类型的元素分配内存,那么这些元素通常(但无法保证)会被初始化为空指针;如果你是为实数类型的元素分配内存,那么这些元素可能(只在某些计算机中)会被初始化为浮点型的零。
malloc() 函数和calloc ()函数的另一点区别是calloc()函数会返回一个由某种对象组成的数组,但malloc()函数只返回一个对象。为了明确是为一个数组分配内存空 间,有些程序员会选用calloc()函数。但是,除了是否初始化所分配的内存空间这一点之外,绝大多数程序员认 为以下两种函数调用方式没有区别:
calloc(numElements ,sizeOfElement);
malloc(numElements *sizeOfElement) ;
需要解释的一点是,理论上(按 照ANSIC标准)指针的算术运算只能在一个指定的数组中进行,但是在实践中,即使C编译程序或翻译器遵循这种规定,许多C程序还是冲破了这种限制。因 此,尽管malloc()函数并不能返回一个数组,它所分配的内存空间仍然能供一个数组使用(对realloc()函数来说同样如此,尽管它也不能返回一 个数组)。
总之,当你在calloc()函数和malloc()函数之间作选择时,你只需考虑是否要初始化所分配的内存空间,而不用考虑函数是否能返回一个数组。
当程序运行过程中malloc了,但是没有free的话,会造成内存泄漏.一部分的内存没有被使用,但是由于没有free,因此系统认为这部分内存还在使用,造成不断的向系统申请内存,是的系统可用内存不断减少.但是,内存泄漏仅仅指程序在运行时,程序退出时,OS将回收所有的资源.因此,适当的重起一下程序,有时候还是有点作用.
G. c语言中的brk和sbrk的区别是什么
一个是标C的 一个是unix 的 brk函数的参数 是 指针 sbrk的参数是 int类型的
H. 请用C语言编写 malloc realloc free 函数。
//IBM的实现,仅供参考
/* Include the sbrk function */
#include <unistd.h>
int has_initialized = 0;
void *managed_memory_start;
void *last_valid_address;
void malloc_init()
{
/* grab the last valid address from the OS */
last_valid_address = sbrk(0);
/* we don't have any memory to manage yet, so
*just set the beginning to be last_valid_address
*/
managed_memory_start = last_valid_address;
/* Okay, we're initialized and ready to go */
has_initialized = 1;
}
struct mem_control_block {
int is_available;
int size;
};
void free(void *firstbyte) {
struct mem_control_block *mcb;
/* Backup from the given pointer to find the
* mem_control_block
*/
mcb = firstbyte - sizeof(struct mem_control_block);
/* Mark the block as being available */
mcb->is_available = 1;
/* That's It! We're done. */
return;
}
void *malloc(long numbytes) {
/* Holds where we are looking in memory */
void *current_location;
/* This is the same as current_location, but cast to a
* memory_control_block
*/
struct mem_control_block *current_location_mcb;
/* This is the memory location we will return. It will
* be set to 0 until we find something suitable
*/
void *memory_location;
/* Initialize if we haven't already done so */
if(! has_initialized) {
malloc_init();
}
/* The memory we search for has to include the memory
* control block, but the user of malloc doesn't need
* to know this, so we'll just add it in for them.
*/
numbytes = numbytes + sizeof(struct mem_control_block);
/* Set memory_location to 0 until we find a suitable
* location
*/
memory_location = 0;
/* Begin searching at the start of managed memory */
current_location = managed_memory_start;
/* Keep going until we have searched all allocated space */
while(current_location != last_valid_address)
{
/* current_location and current_location_mcb point
* to the same address. However, current_location_mcb
* is of the correct type so we can use it as a struct.
* current_location is a void pointer so we can use it
* to calculate addresses.
*/
current_location_mcb =
(struct mem_control_block *)current_location;
if(current_location_mcb->is_available)
{
if(current_location_mcb->size >= numbytes)
{
/* Woohoo! We've found an open,
* appropriately-size location.
*/
/* It is no longer available */
current_location_mcb->is_available = 0;
/* We own it */
memory_location = current_location;
/* Leave the loop */
break;
}
}
/* If we made it here, it's because the Current memory
* block not suitable, move to the next one
*/
current_location = current_location +
current_location_mcb->size;
}
/* If we still don't have a valid location, we'll
* have to ask the operating system for more memory
*/
if(! memory_location)
{
/* Move the program break numbytes further */
sbrk(numbytes);
/* The new memory will be where the last valid
* address left off
*/
memory_location = last_valid_address;
/* We'll move the last valid address forward
* numbytes
*/
last_valid_address = last_valid_address + numbytes;
/* We need to initialize the mem_control_block */
current_location_mcb = memory_location;
current_location_mcb->is_available = 0;
current_location_mcb->size = numbytes;
}
/* Now, no matter what (well, except for error conditions),
* memory_location has the address of the memory, including
* the mem_control_block
*/
/* Move the pointer past the mem_control_block */
memory_location = memory_location + sizeof(struct mem_control_block);
/* Return the pointer */
return memory_location;
}
I. brk函数的具体功能,还有内存的分配
这是留学生c语言的一个知识点。c语言的malloc函数就是调用系统调用brk/sbrk来进行动态内存分配的。brk的参数时调整后的地址,sbrk的参数是希望调整的数量。在调用这2个系统调用时,要注意系统内存分配一般是按页为最小单位,而不是按字节为最小单位的。这个可以自己做测试就知道。
C语言是一门面向过程的、抽象化的通用程序设计语言,广泛应用于底层开发。C语言能以简易的方式编译、处
理低级存储器。C语言是仅产生少量的机器语言以及不需要任何运行环境支持便能运行的高效率程序设计语言。
关于C语言程序设计
过程语言-C程序中的指令是一步一步执行的。
便携的-您可以将C程序从一个平台移动到另一个平台,并在没有任何或最小更改的情况下运行它。
速度- C编程比Java、Python等大多数编程语言都要快。
通用的- C编程可以用来开发操作系统、嵌入式系统、数据库等等。
J. brk()函数与sbrk()函数怎样动态分配空间
brk和sbrk主要的工作是实现虚拟内存到内存的映射.在GNUC中,内存分配是这样的:
每个进程可访问的虚拟内存空间为3G,但在程序编译时,不可能也没必要为程序分配这么大的空间,只分配并不大的数据段空间,程序中动态分配的空间就是从这 一块分配的。如果这块空间不够,malloc函数族(realloc,calloc等)就调用sbrk函数将数据段的下界移动,sbrk函数在内核的管理 下将虚拟地址空间映射到内存,供malloc函数使用。
sbrk不是系统调用,是C库函数。系统调用通常提供一种最小功能,而库函数通常提供比较复杂的功能。
C语言跟内存申请相关的函数主要有 alloc,calloc,malloc,free,realloc,sbrk等.其中alloc是向栈申请内存,因此无需释放. malloc分配的内存是位于堆中的,并且没有初始化内存的内容,因此基本上malloc之后,调用函数memset来初始化这部分的内存空 间.calloc则将初始化这部分的内存,设置为0. 而realloc则对malloc申请的内存进行大小的调整.申请的内存最终需要通过函数free来释放. 而sbrk则是增加数据段的大小;
malloc/calloc/free基本上都是C函数库实现的,跟OS无关.C函数库内部通过一定的结构来保存当前有多少可用内存.如果程序 malloc的大小超出了库里所留存的空间,那么将首先调用brk系统调用来增加可用空间,然后再分配空间.free时,释放的内存并不立即返回给os, 而是保留在内部结构中. 可以打个比方: brk类似于批发,一次性的向OS申请大的内存,而malloc等函数则类似于零售,满足程序运行时的要求.这套机制类似于缓冲.