关于malloc申请的动态内存的问题

时间:2024-01-14 21:08:44

http://bbs.bccn.net/thread-331344-1-1.html

#include<stdio.h>
#include<stdlib.h>
int main(void)
{
    int i;
    int a[5]={1,2,3,4,5};
    int *b=(int *)malloc(sizeof(a));
    if(b==NULL)
    {
        printf("error\n");
        return 1;
    }
    for(i=0;i<5;i++)
    {
        *(b+i)=a[i];
    }
    for(i=0;i<5;i++)
        printf("%d\n",*(b+i));
    free(b);/*此处好像没有释放调,求高手解答*/
    for(i=0;i<5;i++)
        printf("%d\n",*(b+i));
    b=NULL;
    getch();
    return 0;
}

1、free(str) //释放str所指向的空间----告诉系统,这个空间可以被重新分配了。此时str本身的值(即所指向的空间不变),所以为了保证指针的安全性,通常都会在free(str);之后紧跟一句str=NULL,避免str再次操作到原来的空间。
2、在str指向的空间释放给系统之后,原来空间的内容并没有被立即清除掉。但一旦系统将这块空间重新分配给别的变量之后,一旦有变量赋值操作,该空间内的值就会变成新的变量的值。(这也是为什么要进行str=NULL操作,就是为了避免原来的指针str操作新的变量)。

http://blog.chinaunix.net/uid-26611383-id-3802969.html

相信C/C++程序员都用过这个库函数, 这个函数时程序员申请堆中的内存,需要自己手动释放内存,所以这个函数也是Memory Leak的根源。但是malloc一次最多能申请多少内存呢,显然这个跟我们物理内存的大小和
我们的系统,编译器都有一定的关系。已经不记得之前在哪里遇到过这个问题,今天忽然想起来了,于是自己做了个实验。
我的开发环境是Windows7 64位,内存8G,IDE是codeblocks,支持开源,下面是测试代码:

点击(此处)折叠或打开

  1. #include <iostream>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. int64_t maximum = 0;
  5. using namespace std;
  6. int main()
  7. {
  8. cout<<"sizeof(void*) is:"<<(int)sizeof(void*)<<endl;
  9. cout<<"sizeof(int) is:"<<sizeof(int)<<endl;
  10. int64_t blocksize[] = {1024*1024, 1024, 1};
  11. int64_t i, count;
  12. for(i=0;i<3;i++)
  13. {
  14. maximum = 0;
  15. for(count=1;;count++)
  16. {
  17. void *block = (void*)malloc(maximum + blocksize[i] * count);
  18. if(block)
  19. {
  20. maximum = maximum + blocksize[i] *count;
  21. free(block);
  22. }
  23. else
  24. {
  25. break;
  26. }
  27. }
  28. cout << "maxmium malloc size:"<<maximum/1000000<<"M"<<endl;
  29. }
  30. cout << "Hello world!" << endl;
  31. return 0;
  32. }

程序输出如下:
关于malloc申请的动态内存的问题

这个结果是不是很蹊跷,我64位的系统,而且8G的内存,占用了很少,但是这里为什么只分配了2G不到呢,我原来的推想是操作系统保留一部分内存(大概2G),还有差不多6G可以申请,所以这个结果让我很惊讶。于是我又在64bit的linux下,内存4G,用同样代码进行了测试,这次输出是

关于malloc申请的动态内存的问题

这次输出似乎跟预想差不多,4G内存能分配3.5G左右,那么windows下是什么问题导致我8G的内存只能malloc 2G不到呢。细想一下,觉得肯定是编译器的问题,果然我的codeblocks默认的编译器是mingw-32-g++,可能细心的读者已经看到前面的sizeof(void*)的值是4,也就是说在windows下codeblock下默认将该程序编译成32位的了,所以才会出现分配2G不到的内存,感兴趣的可以用其他的64位的编译器测试一下,应该会得到正常值。

总结一下:

程序是32位或者是64位并不是由你的操作系统决定,而是编译器决定,准确的说是决定于编译器和编译选项,64位系统照样可以跑32位的程序。

http://6520874.blog.163.com/blog/static/725827192011710103646201/

C语言的malloc分配的的内存大小

2011-08-10 10:36:46|  分类: 默认分类|举报|字号 订阅

 

没读过malloc()的源码,所以这里纯粹是"理论研究"。

malloc()在运行期动态分配分配内存,free()释放由其分配的内存。malloc()在分配用户传入的大小的时候,还分配的一个相关的用于管理的额外内存,不过,用户是看不到的。所以,

实际的大小 = 管理空间 + 用户空间

那么,这个管理内存放在什么位置呢,它要让free()函数能够找到,这样才能知道有多少内存要释放,所以一种可能的方案是在分配内存的初始部分用若干个字节来存储分配的内存的大小。这里要注意一个问题,就是,在malloc()将这个分配的空间返回给某个指针后,这个指针的使用与其它指针应该是没有差别的,所以,管理空间应该在这个指针指向的空间之外,但又要free()从这个指针可以找到管理信息,所以,这个管理空间的大小放在指针指向的相反方向。故malloc()的具体操作应该就是分配一块内存,在前面若干字节中写入管理信息,然后返回管理信息所占字节之后的地址指针。

=================================================

malloc()工作机制

  malloc函数的实质体现在,它 有一个将可用的内存块连接为一个长长的列表的所谓空闲链表。调用malloc函数时,它沿连接表寻找一个大到足以满足用户请求所需要的内存块。然后,将该 内存块一分为二(一块的大小与用户请求的大小相等,另一块的大小就是剩下的字节)。接下来,将分配给用户的那块内存传给用户,并将剩下的那块(如果有的 话)返回到连接表上。调用free函数时,它将用户释放的内存块连接到空闲链上。到最后,空闲链会被切成很多的小内存片段,如果这时用户申请一个大的内存片段,那么空闲链上可能没有可以满足用户要求的片段了。于是,malloc函数请求延时,并开始在空闲链上翻箱倒柜地检查各内存片段,对它们进行整理,将相邻的小空闲块合并成较大的内存块。

malloc()在操作系统中的实现

  在 C 程序中,多次使用malloc () 和 free()。不过,您可能没有用一些时间去思考它们在您的操作系统中是如何实现的。本节将向您展示 malloc 和 free 的一个最简化实现的代码,来帮助说明管理内存时都涉及到了哪些事情。
  在大部分操作系统中,内存分配由以下两个简单的函数来处理:
  void *malloc (long numbytes):该函数负责分配 numbytes 大小的内存,并返回指向第一个字节的指针。
  void free(void *firstbyte):如果给定一个由先前的 malloc 返回的指针,那么该函数会将分配的空间归还给进程的“空闲空间”。

  malloc_init 将是初始化内存分配程序的函数。它要完成以下三件事:将分配程序标识为已经初始化,找到系统中最后一个有效内存地址,然后建立起指向我们管理的内存的指针。这三个变量都是全局变量:

关于malloc申请的动态内存的问题        //清单 1. 我们的简单分配程序的全局变量
关于malloc申请的动态内存的问题
关于malloc申请的动态内存的问题        int has_initialized = 0;
关于malloc申请的动态内存的问题        void *managed_memory_start;
关于malloc申请的动态内存的问题        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%。

下面是我的测试代码。(根据各方面资料,windows好像分配到2G就差不多是极限了。但Linux好像就没这种限制了。)

 #include<stdio.h>
#include<stdlib.h>
int main()
{
int *a,*b,*c,*d,*e,*f,*g,*h,*i,*j;
printf("%d\n",sizeof(int));
a=(int *)malloc(*sizeof(int));
if(a==NULL) printf("分配内存a失败!\n");
else printf("分配内存a成功!\n"); b=(int *)malloc(*sizeof(int));
if(b==NULL) printf("分配内存b失败!\n");
else printf("分配内存b成功!\n"); c=(int *)malloc(*sizeof(int));
if(c==NULL) printf("分配内存c失败!\n");
else printf("分配内存c成功!\n"); d=(int *)malloc(*sizeof(int));
if(d==NULL) printf("分配内存d失败!\n");
else printf("分配内存d成功!\n"); e=(int *)malloc(*sizeof(int));
if(e==NULL) printf("分配内存e失败!\n");
else printf("分配内存e成功!\n"); f=(int *)malloc(*sizeof(int));
if(f==NULL) printf("分配内存f失败!\n");
else printf("分配内存f成功!\n"); g=(int *)malloc(*sizeof(int));
if(g==NULL) printf("分配内存g失败!\n");
else printf("分配内存g成功!\n"); h=(int *)malloc(*sizeof(int));
if(h==NULL) printf("分配内存h失败!\n");
else printf("分配内存h成功!\n"); i=(int *)malloc(*sizeof(int));
if(i==NULL) printf("分配内存i失败!\n");
else printf("分配内存i成功!\n"); j=(int *)malloc(*sizeof(int));
if(j==NULL) printf("分配内存j失败!\n");
else printf("分配内存j成功!\n"); free(a);
free(b);
free(c);
free(d);
free(e);
free(f);
free(g);
free(h);
free(i);
free(j);
return ;
}