• 面试十三、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 释放内存的时候,会把内存归还给操作系统,内存得到真正的释放.

  • 相关阅读:
    数据库课后作业
    CVE-2023-25194 Kafka JNDI 注入分析
    好奇喵 | Rust编程语言的简单了解~
    【微信小程序】获取/设置屏幕亮度
    【Java毕设项目】基于SpringBoot+Vue教务管理系统的开发与实现
    程序开发中表示密码时使用 password 还是 passcode?
    Educational Codeforces Round 154 (Rated for Div. 2)【A-E】【详细题解,F未完待续】
    cocos2d-lua:骨骼动画的使用
    avi怎么转换成视频?
    Android NDK 实现视音频播放器源码
  • 原文地址:https://blog.csdn.net/leimeili/article/details/138034058