• 内存分配(malloc,new,VirtualAlloc,HeapAlloc,GlobalAlloc,LocalAlloc)区别与注意


    malloc()
    头文件:#include <malloc.h> 或 #include <alloc.h> (注意:alloc.h 与 malloc.h 的内容是完全一致的。)
    功能:分配长度为num_bytes字节的内存块
    说明:如果分配成功则返回指向被分配内存的指针,否则返回空指针NULL。
    当内存不再使用时,应使用free()函数将内存块释放。

    C运行库中的动态内存分配函数,主要用于ANSI C(C语言的标准)程序中,是标准库函数。WINDOWS程序基本不再使用这种方法进行内存操作,因为它比WINDOWS内存分配函数少了一些特性,如整理内存

    注:
     一般 malloc 的实现并不是从系统的堆中分配的, 而是从编译器连接的运行库自己管理的堆中, 在 Win32 平台上的开发工具的编译结果中, 通常是用 HeapCreate 创建一个堆, 用 HeapAlloc 和 HeapRealloc 维护堆的空间增长, 在最后用 HeapDestroy 删除堆. 而在用 malloc 分配, 用 free 释放时则由运行库的代码负责从这个堆中分配空间和向这个堆中归还空间, 并维护这个堆中的数据结构. 由于 malloc 堆的管理是由运行库自己管理的, 所在当我们使用静态运行库时, 如果在一个 DLL 中用 malloc 分配了内存而在另一个 DLL 中用 free 去释放它, 通常都会产生问题. 这是因为每个DLL都连接了一份运行库的代码, 从而也都有一个自己的局部堆, 而在用 free 释放时它会假设这块内存是在自己的堆中分配的, 从而导致错误. 而通过 GlobalAlloc 和 LocalAlloc 分配的内存不存在这个问题.

     

    new()
    标准C++一般使用new语句分配动态的内存空间,

    需要申请数组时,可以直接使用new int[8]这样的方式,释放该方法申请的内存空间使用对应的delete语句,需要释放的内存空间为一个数组,则使用delete [] ary;

    要访问new所开辟的结构体空间,无法直接通过变量名进行,只能通过赋值的指针进行访问.

    new在内部调用malloc来分配内存,delete在内部调用free来释放内存。

     

     

    HeapALloc()

    LPVOID HeapAlloc(HANDLE hHeap,DWORD dwFlags,SIZE_T dwBytes);

    windows系统的函数
    HeapALloc是从堆上分配一块内存,且如果没有连续的空间能满足分配的大小,会导致分配失败,该分配方法是从一指定地址开始分配,而不像GloabalAlloc是从全局堆上分配,这个有可能是全局,也有可能是局部

    HeapDestroy 删除堆

    VirtualAlloc()
    PVOID VirtualAlloc(PVOID pvAddress, SIZE_T dwSize, DWORD fdwAllocationType, DWORD fdwProtect)
    VirtualAlloc是Windows提供的API,通常用来分配大块的内存。例如如果想在进程A和进程B之间通过共享内存的方式实现通信,可以使用该函数(这也是较常用的情况)。不要用该函数实现通常情况的内存分配。该函数的一个重要特性是可以预定指定地址和大小的虚拟内存空间。例如,希望在进程的地址空间中第50MB的地方分配内存,那么将参数 50*1024*`1024 = 52428800 传递给pvAddress,将需要的内存大小传递给dwSize。如果系统有足够大的闲置区域能满足请求,则系统会将该块区域预订下来并返回预订内存的基地址,否则返回NULL。
    使用VirtualAlloc分配的内存需要使用VirtualFree来释放。

    VirtualAlloc
    BufferData = (uint8_t*)VirtualAlloc(NULL, BufferLength, MEM_COMMIT, PAGE_READWRITE);
    if (BufferData!=NULL)
    {
    VirtualFree(BufferData,0,MEM_RELEASE);
    BufferData = NULL;
    }
    大量的数据缓冲区,动态分配内存的空间。使用VirtualAlloc函数来分配内存的速度要比全局内存要快。

     GlobalAlloc() LocalAlloc()

    HLOCAL LocalAlloc( UINT uFlags, SIZE_T uBytes ); 
    GlobalAlloc( UINT uFlags, SIZE_T uBytes ); 

    //GHND 申请一块带有GMEM_MOVEABLE和GMEM_ZEROINIT标志的内存
    //GMEM_MOVEABLE 可移动 返回内存对象的句柄 用GlobalLock将句柄转换为指针
    //GMEM_FIXED 固定 返回内存指针
    //GMEMZEROINIT 初始化为0
    // GPTR申请一块带有GMEM_FIXED和GMEM_ZEROINIT标志的内存

    void* p = ::GlobalAlloc(GPTR, nSize);


    在16位Windows中是有区别的,因为在16位windows用一个全局堆和局部堆来管理内存,每一个应用程序或dll装入内存时,代码段被装入全局 堆,而系统又为每个实例从全局堆中分配了一个64kb的数据段作为该实例的局部堆,用来存放应用程序的堆栈和所有全局或静态变量。 LocalAlloc用于在局部堆 GlobalAlloc用于全局堆中分配内存。 
    由于每个进程的局部堆很小,所以在局部堆中分配内存会受到空间的限制。但这个堆是每个进程私有的,相对而言分配数据较安全,数据访问出错不至于影响到整个系统。 
    而在全局堆中分配的内存是为各个进程共享的,每个进程只要拥有这个内存块的句柄都可以访问这块内存,但是每个全局内存空间需要额外的内存开销,造成分配浪费。而且一旦发生严重错误,可能会影响到整个系统的稳定。 
    不过在Win32中,每个进程都只拥有一个省缺的私有堆,它只能被当前进程访问。应用程序也不可能直接访问系统内存。所以在Win32中全局堆和局部堆都 指向进程的省缺堆。用LocalAlloc/GlobalAlloc分配内存没有任何区别。甚至LocalAlloc分配的内存可以被 GlobalFree释放掉。

    它们之间的区别主要有以下几点:
    1、GlobalAlloc()函数在程序的堆中分配一定的内存,是Win16的函数,对应于系统的全局栈,而在Win32中全局栈和局部堆的区别已经不存在了,因此不推荐在Win32中使用该函数。
    2、malloc()是标准库函数,而new则是运算符,它们都可以用于申请动态内存。
    3、new()实际上调用的是malloc()函数。
    4、new运算符除了分配内存,还可以调用构造函数,但是malloc()函数只负责分配内存。
    5、对于非内部数据类型的对象而言,只使用malloc()函数将无法满足动态对象的要求,因为malloc()函数不能完成执行构造函数的任务。
    6、malloc(); 和 HeapAlloc(); 都是从堆中分配相应的内存,不同的是一个是c run time的函数,一个是windows系统的函数, 对于windows程序来说,使用HeapAlloc();会比malloc();效率稍稍高一些。

    错误可能
    1..内存分配成功却没有初始化
    2.越界
    3忘记释放内存
    4释放内存后继续使用

    注意 数据结构设计
    申请内存后判断指针是否为空
    释放后将指针置为空
    动态申请与释放一定要配对,以防内存泄漏
    不要反悔指向“栈内存”的指针或引用

    未完,之后会加入一些实例化代码

  • 相关阅读:
    centos7 安装mysql
    Nginx安装及配置详解
    nginx安装
    JSON Web Token
    优先队列
    小程序遮罩层禁止页面滚动(遮罩层内部可以滚动)
    H5中接入微信支付
    如何使用less预编译
    在methods中使用filter
    根据当前时间获取上一个月的时间
  • 原文地址:https://www.cnblogs.com/Crisczy/p/7271478.html
Copyright © 2020-2023  润新知