面试十三、malloc 、calloc、realloc以及new的区别

// 1 . 静态内存分配
 .bss 存储未初始化的全局变量和静态变量,在编译时被分配空间,但不会被初始化。在程序启动时,系统会将.bss段的数据初始化为零或者空值
 .data (静态数据区) : 存储已经初始化的全局变量和静态变量(静态局部和静态全局)的值

 栈:存储函数的局部变量和函数调用的参数
 堆:存储通常用于动态分配的内存
 .. image:: F:\C++\C++\STL\images\img.png

// 2. 动态内存分配
   .. image:: F:\C++\C++\STL\images\img_1.png
   .. image:: F:\C++\C++\STL\images\img_2.png
   .. image:: F:\C++\C++\STL\images\img_3.png
   malloc/calloc/realloc/free区别:
       (1) malloc 函数:从堆上分配内存,内存不会被修改或者清空,返回首字节的地址,返回void*,失败返回nullptr
           int* str = (int *)malloc(sizeof(int));

       (2) calloc 函数: 从堆上分配内存并清零,malloc和realloc开辟空间后的数据为随机值
           函数原型   void *calloc(size_t nitems, size_t size)
           nitems -- 要被分配的元素个数。
           size -- 元素的大小。
           int *p calloc(5,sizeof(int))

      (3) realloc 函数:在之前分配的内存块的基础上,将内存重新分配为更大或者更小的部分
           第一个参数指向原内存块的指针,第二个是请求的大小。重新分配的块大小和第一个参数引用的块大小不同。返回值是指向重新分配的内存的指针
           函数原型:void *realloc(void *ptr , size_t size);
           a. 当第一个参数为nullptr时,功能等价于malloc
           b. 分两种情况:
               1. 原地址空间有连续的内存,则直接扩大,返回原地址的指针
               2. 原地址空间没有连续的内存,则重新开辟一片空间,将数据拷贝到新空间,释放原空间,返回新地址指针(注意显式释放问题,引起二次释放的问题)
                  原地址的指针已经被释放了,小心第二次释放

       (4) 释放内存free
             void free(void *p)   ,释放之前有调用 calloc、malloc 或 realloc 所分配的内存空间,*p指针指向一个要释放内存的内存块。
             存在问题:
               1. 二次释放,如realloc新开辟空间,则会导致程序崩溃
               2. free释放部分空间,程序会崩溃。
                如:
                   int* p = (int *)malloc(sizeof(int));
                   p++;
                   free(p);
               3. 忘记释放
               4. free函数只是释放了内存空间,但不会修改指针本身的值。因此,调用 free 后,指针 p 仍然指向之前分配的内存地址
                   指针设置为 nullptr,以避免出现悬空指针的问题


new与operator new的区别
   new 调用过程
       1.首先调用operator new 分配内存  2.然后调用对象的构造函数构造对象
       2. operator new 的实现 ,调用malloc分配内存,成功返回void * 类型指针,失败返回bad_alloc
           与malloc区别:  malloc+失败抛异常实现
               void * operator new(std::size_t size) throw(std::bad_alloc)
               {
                   if (size == 0)
                   {
                       size = 1;
                   }
                   void* p;
                   while ((p = ::malloc(size)) == 0)
                   { //采用 malloc 分配空间
                       std::new_handler nh = std::get_new_handler();
                       if (nh)
                           nh();
                       else
                           throw std::bad_alloc();
                   }
                   return p;
               }


       3. 调用定位new在开辟内存上构造对象
           void* memory = operator new(sizeof(MyClass));
           MyClass* myObject = new(memory) MyClass();

           void* CTest::operator new(size_t size, void* memory)
               {
                size;
                std::cout << "执行了类中的重载 placement new 函数。" << std::endl;
                return pbuffer;
               }

       4. new int[10]原理
               a. 调用operator new[]函数,在operator new[]中实际调用operator new函数完成10个对象空间的申请
               b. 在申请的空间上执行10构造函数

   delete 调用过程:
       1.在空间上执行析构函数,完成对象中资源的清理工作
       2.调用operator delete数释放对象的空间

       3. operator delete 释放内存
           与free区别:
               1. 不会造成二次释放
               2. 不会释放部分内存

       void operator delete (void* pUserData){
           _CrtMemBlockHeader * pHead;

           RTCCALLBACK(_RTC_Free_hook,(pUserData,0));

           if(pUserData== NULL)
               return;

               _mlock(_HEAP_LoCK);
           __TRY
               pHead=pHdr(pUserData);
               _ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockuse));
               _free_dbg( pUserData,pHead->nBlockUse); // free

           __FINALLY
               _munlock(_HEAP_LOCK);
           __END_TRY_FINALLY
           return;
       }

       4. delete[]原理
           a.在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理
           b.调用operator delete[]放空间,实际在operator delete[]中调用operator delete释放空间


       5.删除定位placement new
           直接调用对象的析构函数


           1.malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符。它们都可用于申请动态内存和释放内存。
           2.对于非内部数据类型的对象而言,光用maloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。 由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free。
           3.new操作符内存分配成功时,返回的是对象类型的指针,类型严格与对象匹配,无须进行类型转换;malloc内存分配成功则是返回void * ,需要通过强制类型转换将void*指针转换成我们需要的类型。
           4.new内存分配失败时,会抛出bac_alloc异常,它不会返回NULL;malloc分配内存失败时返回NULL。
           5.使用new操作符申请内存分配时无须指定内存块的大小,编译器会根据类型信息自行计算;malloc则需要显式地指出所需内存的尺寸

malloc的内存分配方式:

  • 方式一:通过 brk() 系统调用从堆分配内存
  • 方式二:通过 mmap() 系统调用在文件映射区域分配内存;
  • 如果用户分配的内存小于 128 KB,则通过 brk() 申请内存;
  • 如果用户分配的内存大于 128 KB,则通过 mmap() 申请内存;

        malloc() 在分配内存的时候,并不是老老实实按用户预期申请的字节数来分配内存空间大小,而是会预分配更大的空间作为内存池

        malloc(1) 实际上预分配 132K 字节的内存。因为要加上内存块的描述信息.

  • malloc 通过 brk() 方式申请的内存,free 释放内存的时候,并不会把内存归还给操作系统,而是缓存在 malloc 的内存池中,待下次使用
  • malloc 通过 mmap() 方式申请的内存,free 释放内存的时候,会把内存归还给操作系统,内存得到真正的释放.

  • 12
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值