精华内容
下载资源
问答
  • 内存分配

    千次阅读 2012-03-14 22:08:48
     3,内存分配成功后,初始化,对内存的使用超过了边界。解决办法:注意边界条件  4,使用分配的内存忘记释放内存。解决办法:释放与申请相对应。  5,释放继续使用内存,解决办法:释放将指向内存

    内存分配的过程中容易出现以下的错误:

       1,内存未分配成功,却在程序中使用了,解决办法是:使用前先进行判断

       2,内存分配成功后,未进行初始化,解决办法是:初始化为常量值

       3,内存分配成功后,初始化后,对内存的使用超过了边界。解决办法:注意边界条件

       4,使用分配的内存后忘记释放内存。解决办法:释放与申请相对应。

       5,释放后继续使用内存,解决办法:释放后将指向内存的指针赋值为NULL

    c语言中的内存分配:

           C语言中采用malloc()和free()函数进行内存的分配和释放,当然还有其他内存分配的函数(calloc()和realloc())。此文只对malloc()和free()函数进行了讨论。

         calloc()函数:void* calloc(size_t num, size_t size_of_element)

                           说明:    其中num为元素的个数,size_of_element为每个元素所占的空间大小,申请的空间大小为:num*size_of_element,  同时每个空间被初始化为零。

    #include<stdio.h>
    #include<stdlib.h>
    int main(void)
    {
    	int i;
    	int *pn=(int *)calloc(10,sizeof(int));
    	for(i=0;i<10;i++)
    		printf("%3d",*pn++);
    	printf("\n");
    	free(pn);
    	return 0;
    } 

          realloc()函数: void*  realloc(void* mem_address, size_t newsize)

    #include<stdio.h>
    #include<stdlib.h>
    int main()
    {
    	int i;
    	int *pn=(int *)malloc(5*sizeof(int));
    	printf("%p\n",pn);
    	for(i=0;i<5;i++)
    		scanf("%d",&pn[i]);
    	pn=(int *)realloc(pn,10*sizeof(int));
    	printf("%p\n",pn);
    	for(i=0;i<5;i++)
    		printf("%3d",pn[i]);
    	printf("\n");
    	free(pn);
    	return 0;
    } 
                          说明:  按照newsize的大小申请一个空间,将原来数据从地址mem_address中拷贝到新的地方,释放原来的内存,同时返回指向新的内存的指针。 realloc失败的时候,返回NULL;   realloc失败的时候,原来的内存不改变,不会释放也不会移动;传递给realloc的指针必须是先前通过malloc(), calloc(), 或realloc()分配的;   假如原来的内存后面还有足够多剩余内存的话,realloc的内存=原来的内存+剩余内存,realloc还是返回原来内存的地址; 假如原来的内存后面没有足够多剩余内存的话,realloc将申请新的内存,然后把原来的内存数据拷贝到新内存里,原来的内存将被free掉,realloc返回新内存的地址;   如果size为0,效果等同于free()。这里需要注意的是只对指针本身进行释放,例如对二维指针**a,对a调用realloc时只会释放一维,使用时谨防内存泄露。

    一、malloc()和free()的基本概念以及基本用法:

    1、函数原型及说明:
             void *   malloc(long NumBytes):该函数分配了NumBytes个字节,并返回了指向这块内存的指针。如果分配失败,则返回一个空指针(NULL)。在写代码的过程一定要对内存分配失败与否进行判断。

             void      free(void *FirstByte):该函数是将之前用malloc分配的空间还给程序或者是操作系统,也就是释放了这块内存,让它重新得到自由。

            char *pChar = NULL;
    	pChar = (char *)malloc(10*sizeof(char));
    	if (NULL == pChar)   //check the malloc()'s return
    	{
    		cout<<"memory failed!"<<endl;
    		exit(1);
    	}
    	//do something 
    	free(pChar);
            pChar = NULL;

    
    

    2     关于函数使用需要注意的一些地方:       A、申请了内存空间后,必须检查是否分配成功。       B、当不需要再使用申请的内存时,记得释放;释放后应该把指向这块内存的指针指向NULL,防止程序后面不小心使用了它。       C、这两个函数应该是配对。如果申请后不释放就是内存泄露;如果无故释放那就是什么也没有做。释放只能一次,如果释放两次及两次以上会出现错误(释放空指针例外,释放空指针其实也等于啥也没做,所以释放空指针释放多少次都没有问题)。        D、虽然malloc()函数的类型是(void *),任何类型的指针都可以转换成(void*),但是最好还是在前面进行强制类型转换,因为这样可以躲过一些编译器的检查。3    深层次理解malloc()和free()

    3.1、malloc()到底从哪里得到了内存空间?从堆里面获得空间。也就是说函数返回的指针是指向堆里面的一块内存。操作系统中有一个记录空闲内存地址的链表。当操作系统收到程序的申请时,就会遍历该链表,然后就寻找合适的空间(不同的内存管理办法采用不同的分配原则),然后就将该结点从空闲结点链表中删除,并将该结点的空间分配给程序。就是这样!(具体的怎么去分配的可以看有关OS的书中内存管理的相关章节,内存管理有:分页式管理,分段式管理和两种方式结合)     

     3.2、什么是堆:堆是大家共有的空间,分全局堆和局部堆。全局堆就是所有没有分配的空间,局部堆就是用户分配的空间。堆在操作系统对进程初始化的时候分配,运行过程中也可以向系统要额外的堆,但是记得用完了要还给操作系统,要不然就是内存泄漏。什么是栈:栈是线程独有的,保存其运行状态和局部自动变量的。栈在线程开始的时候初始化,每个线程的栈互相独立。每个函数都有自己的栈,栈被用来在函数之间传递参数。操作系统在切换线程的时候会自动的切换栈,就是切换SS/ESP寄存器。栈空间不需要在高级语言里面显式的分配和释放。

    栈是由编译器自动分配释放,存放函数的参数值、局部变量的值等。操作方式类似于数据结构中的栈。堆一般由程序员分配释放,若不释放,程序结束时可能由OS回收。注意这里说是可能,并非一定。所以我想再强调一次,记得要释放!注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。所以,举个例子,如果你在函数上面定义了一个指针变量,然后在这个函数里申请了一块内存让指针指向它。实际上,这个指针的地址是在栈上,但是它所指向的内容却是在堆上面的!这一点要注意!所以,再想想,在一个函数里申请了空间后,比如说下面这个函数:程序代码:

    void Function(void)
    {
            char *p = (char *)malloc(100 * sizeof(char));
    }




    就这个例子,千万不要认为函数返回,函数所在的栈被销毁指针也跟着销毁,申请的内存也就一样跟着销毁了!这绝对是错误的!因为申请的内存在堆上,而函数所在的栈被销毁跟堆完全没有啥关系。所以,还是那句话:记得释放
             3.3、free()到底释放了什么

             free()释放的是指针指向的内存!注意!释放的是内存,不是指针!这点非常非常重要!指针是一个变量,只有程序结束时才被销毁。释放了内存空间后,原来指向这块空间的指针还是存在!只不过现在指针指向的内容的垃圾,是未定义的,所以说是垃圾。因此,前面我已经说过了,释放内存后把指针指向NULL,防止指针在后面不小心又被解引用了。非常重要啊这一点!

      
    	free(pChar);
            pChar = NULL;    //赋值为NULL

    4   malloc()以及free()的机制:


            仔细看一下free()的函数原型,也许也会发现似乎很神奇,free()函数非常简单,只有一个参数,只要把指向申请空间的指针传递
    给free()中的参数就可以完成释放工作!这里要追踪到malloc()的申请问题了。申请的时候实际上占用的内存要比申请的大。因为超出的空间是用来记录对这块内存的管理信息。先看一下在《UNIX环境高级编程》中第七章的一段话:

    大多数实现所分配的存储空间比所要求的要稍大一些,额外的空间用来记录管理信息——分配块的长度,指向下一个分配块的指针等等。这就意味着如果写过一个已分配区的尾端,则会改写后一块的管理信息。这种类型的错误是灾难性的,但是因为这种错误不会很快就暴露出来,所以也就很难发现。将指向分配块的指针向后移动也可能会改写本块的管理信息。

    以上这段话已经给了我们一些信息了。malloc()申请的空间实际我觉得就是分了两个不同性质的空间。一个就是用来记录管理信息的空间,另外一个就是可用空间了。而用来记录管理信息的实际上是一个结构体。在C语言中,用结构体来记录同一个对象的不同信息是
    下面看看这个结构体的原型:
    程序代码:

    struct mem_control_block {
               int is_available;  
               int size;//这是实际空间的大小
         };





    对于size,这个是实际空间大小。

    所以,free()就是根据这个结构体的信息来释放malloc()申请的空间!而结构体的两个成员的大小我想应该是操作系统的事了。但是这里有一个问题,malloc()申请空间后返回一个指针应该是指向第二种空间,也就是可用空间!不然,如果指向管理信息空间的话,写入的内容和结构体的类型有可能不一致,或者会把管理信息屏蔽掉,那就没法释放内存空间了,所以会发生错误!
    好了!下面看看free()的源代码,我自己分析了一下,觉得比起malloc()的源代码倒是容易简单很多。
    程序代码:
    void free(void *ptr)
    {
    struct mem_control_block *free;
    free = ptr - sizeof(struct mem_control_block);
    free->is_available = 1;
    return;
    }

    c++语言中的new和delete运算符

    注意此处的new和delete是运算符而不是函数。c++中如果使用malloc()和free(),不能调用构造函数和析构函数,这破坏了空间分配、初始化的功能。所以引入了new和delete。

    new的用法



    1.     开辟单变量地址空间

             1)new int;  //开辟一个存放数组的存储空间,返回一个指向该存储空间的地址.int *a = new int 即为将一个int类型的地址赋值给整型指针a. 

             2)int *a = new int(5) 作用同上,但是同时将整数赋值为5

    2.     开辟数组空间

              一维: int *a = new int[100];开辟一个大小为100的整型数组空间

              二维: int **a = new int[5][6]

              三维及其以上:依此类推.

             一般用法: new 类型 [初值]

    delete用法:

              1. int *a = new int;

                   delete a;   //释放单个int的空间

              2.int *a = new int[5];

                   delete [] a; //释放int数组空间

              要注意new和delete是一对,new[]和delete[]是一对。

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

              用new和delete可以动态开辟,撤销地址空间.在编程序时,若用完一个变量(一般是暂时存储的数组),下次需要再用,但却又想省去重新初始化的功夫,可以在每次开始使用时开辟一个空间,在用完后撤销它.




    
    
    
    
    
    
    
    
    展开全文
  • ,包含在库函数 stdlib.h中,作用是在内存的堆区分配一个大小为size的连续空间,如果分配内存成功,函数返回新分配内存的首地址,否则,返回NULL,注意:鉴于上述这点,一般在写程序需要判断分配内存是否成功,如下...
  • 内存分配成功,但并未初始化

    千次阅读 2017-07-15 14:52:24
    内存分配成功,但并未初始化
    内存分配成功,但并未初始化


    (1)犯这个错误往往是由于没有初始化的概念或者是以为内存分配好之后其值自然为0。
    (2)在定义一个变量时,第一件事就是初始化。你可以把它初始化为一个有效的值,比如:
      int i = 10;
     char *p = (char *)malloc(sizeof(char)); 
    但是往往这个时候我们还不确定这个变量的初值,这样的话可以初始化为0 或NULL。 
    int i = 0; 
    char *p = NULL; 
    如果定义的是数组的话,可以这样初始化: int a[10] = {0}; 或者用memset 函数来初始化为0: 
    memset(a,0,sizeof(a)); memset 函数有三个参数,第一个是要被设置的内存起始地址;第二个参数是要被设置的值;第三个参数是要被设置的内存大小,单位为byte。这里并不想过多的讨论memset 函数的用法,如果想了解更多,请参考相关资料。
    展开全文
  • ,包含在库函数 stdlib.h中,作用是在内存的堆区分配一个大小为size的连续空间,如果分配内存成功,函数返回新分配内存的首地址,否则,返回NULL,注意:鉴于上述这点,一般在写程序需要判断分配内存是否成功,如下...
  • 自动内存管理内存分配内存分配和回收策略java技术体系中所提倡的自动内存管理最终可以归结为自动化解决了两个问题:给对象分配内存以及回收分配给对象的内存。,关于内存的回收,之前我们已经使用了大量的篇幅介绍...

    自动内存管理内存分配:内存分配和回收策略

    java技术体系中所提倡的自动内存管理最终可以归结为自动化解决了两个问题:给对象分配内存以及回收分配给对象的内存。,关于内存的回收,之前我们已经使用了大量的篇幅介绍了这个东西。接下来我们会探讨下自动化内存分配。

    对象的内存分配,往大了讲,就是在堆上分配。

    接下来我们将会讲解几条最普遍的内存分配策略。

    对象优先在Eden分配

    大多数情况下,对象在新生代Eden区中分配。当Eden区没有足够空间进行分配时,虚拟机将发生一次GC.

    大对象直接进入老生代

    所谓的大对象是指,需要大量连续内存空间的java对象,最典型的大对象就是那种很长的字符串以及数组。大对象对虚拟机的内存分配来说是一个坏消息(替jvm抱怨一句,比遇到大对象更加坏的消息就是遇到一群朝生夕灭的短命大对象,写程序的时候应当避免),经常出现大对象容易导致内存还有不少空间时就提前触发垃圾收集以获取足够的连续空间来安置它们。

    长期存活的对象将进入老生代

    既然虚拟机采用了分代收集的思想来管理内存,那么内存回收时就必须能识别哪些对象应该放在新生代,哪些对象应放在老生代中。为了做到这点,虚拟机给每个对象定义了一个对象年龄计数器。如果对象在Eden区出生并经过第一次Minor GC后仍然存活,并且能被Suvivor容纳的话,将被移动到Suvivor空间中,并且对象年龄设为1.对象在Survivor区中每熬过一次Minor GC,年龄就增加1岁,当它的年龄增加到一定程度(默认为15岁),就将会被晋升到老生代中。对象晋升老生代的年龄阈值可以设定。

    动态对象年龄判定

    为了能够更好的适应不同程序的内存状况,虚拟机并不是永远的要求对象的年龄必须达到了设置的阈值才能晋升老生代,如果在Suvivor空间中相同年龄所有对象大小的总和大于Suvivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入老生代,无须等待阈值要求的年龄。

    空间分配担保

    在学习JVM垃圾收集机制的时候,我们就知道了新生代采用复制算法,但是会造成空间的浪费,故而提出了一种“空间担保机制”来提高复制算法的空间利用率,使复制算法的浪费从50%降到了10%。而老年代的内存就充当了这个担保者,并且由于没有其他内存来担保老年代,所以老年代如果不想产生空间内存碎片那么只能使用“标记-整理”算法了。看到这,我们其实心里肯定有疑问——如何保证老年代有足够的空间来执行空间担保机制呢?Full GC,是否触发根据经验值判断,即使不允许担保失败,也有可能发生担保失败。

    当发生YGC的时候,JVM都会检测之前每次晋升到老年代的对象的平均大小是否大于老年代的剩余内存空间,如果大于,则触发Full GC;如果小于,则查看HandlePromotionFailure设置是否允许担保失败;如果允许,则不会触发Full GC,反之,触发Full GC,保证老年代有足够的空间支持空间分配担保成功。

    其实在每次GC发生的时候,我们也不知道到底会有多少对象被回收,又有多少对象能存活。故而只好取之前每次回收晋升到老年代的对象的平均值作为经验值来判断,但是如果某次GC后存活对象激增,任然会导致担保失败,那么只能重新进行Full GC了,虽然这样会绕个圈子,但是大部分情况下还是会将HandlePromotionFailure的值设为true,从而 避免Full GC过于频繁。换句话说,就是大部分情况,允许担保失败。

    展开全文
  • 计算机内存分配

    千次阅读 2015-03-03 23:33:22
    计算机内存分配,程序的内存空间,堆与栈的比较,new/delete与malloc/free详解

    从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量。

    在栈上创建。 在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
    从堆上分配,亦称动态内存分配 。程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存期由程序员决定,使用非常灵活,但如果在堆上分配了空间,就有责任回收它,否则运行的程序会出现内存泄漏,频繁地分配和释放不同大小的堆空间将会产生堆内碎块。

    程序的内存空间:

    一个程序将操作系统分配给其运行的内存块分为5个区域,如下图所示。

    栈区(stack area)

    程序内存空间

    堆区(heap area)

    全局数据区(data area)

    文字常量区

    代码区(code area)



    一个由C/C++编译的程序占用的内存分为以下几个部分,
    • 栈区(stack)
    由编译器自动分配释放,一般使用寄存器来存取,效率很高,但是分配的内存容量有限。一般暂时存放为运行函数而分配的局部变量,函数参数,返回数据,返回地址等。操作方式类似数据结构中的栈。
    • 堆区(heap)
    亦称动态内存。如malloc和new申请的内存空间。动态内存的生存期一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。分配方式类似于链表。
    • 全局区(static)

    从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。存放全局变量、静态数据、常量。程序结束后由系统释放

    • 文字常量区

    常量字符串就是放在这里的, 程序结束后由系统释放。
    • 程序代码区
    存放函数体(类成员函数和全局函数)的二进制代码。因为存储是数据和代码分开存储的


    下面给出例子程序,
    int a = 0; //全局初始化区
    char *p1; //全局未初始化区
    main() {
      int b; //栈
      char s[] = "abc"; //栈
      char *p2; //栈
      char *p3 = "123456"; //123456\0在常量区,p3在栈上。
      static int c =0; //全局(静态)初始化区
      p1 = (char *)malloc(10); //p1,p2本身在栈中
      p2 = (char *)malloc(20); //分配得来的10和20字节的区域就在堆区。
      strcpy(p1, "123456"); //123456\0放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。


    堆与栈的比较:

    1) 申请方式
    • :由系统自动分配。 例如,声明在函数中一个局部变量 int b; 系统自动在栈中为b开辟空间。
    • :需要程序员自己申请,并指明大小,在C中malloc函数,C++中是new运算符。如p1 = (char *)malloc(10); p1 = new char [10]; 如p2 = (char *)malloc(10); p2 = new char [20]; 但是注意p1、p2本身是在栈中的。

    2) 申请后系统的响应
    • :只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。
    • :首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序。对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的delete语句才能正确的释放本内存空间。由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。

    3) 申请大小的限制 
    • :在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在 WINDOWS下,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。
    • :堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。

    4) 申请效率的比较
    • :由系统自动分配,速度较快。但程序员是无法控制的。
    • :是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便。

    5) 堆和栈中的存储内容 
    • :在函数调用时,第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句)的地址,然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈的,然后是函数中的局部变量。注意静态变量是不入栈的 (静态数据在全局区)。当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行。
    • :一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容有程序员安排。

    6) 小结
    堆和栈的主要区别由以下几点:
    • 管理方式:对于栈来讲,是由编译器自动管理,无需我们手工控制;对于堆来说,释放工作由程序员控制,容易产生memory leak。memory leak:内存泄漏,用动态存储分配函数动态开辟的空间,在使用完毕后未释放,结果导致一直占据该内存单元。直到程序结束。
    • 空间大小:一般来讲在32位系统下,堆内存可以达到4G的空间,从这个角度来看堆内存几乎是没有什么限制的。但是对于栈来讲,一般都是有一定的空间大小的,例如,在VC6下面,默认的栈空间大小是1M。当然,这个值可以修改。分配大量的内存空间,用堆比较灵活。
    • 碎片问题:对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈来讲,则不会存在这个问题,因为栈是先进后出的队列,他们是如此的一一对应,以至于永远都不可能有一个内存块从栈中间弹出,在他弹出之前,在他上面的后进的栈内容已经被弹出。
    • 生长方向:对于堆来讲,生长方向是向上的,也就是向着内存地址增加的方向;对于栈来讲,它的生长方向是向下的,是向着内存地址减小的方向增长。
    • 分配方式:堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的,他的动态分配是由编译器进行释放,无需我们手工实现。
    • 分配效率:栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是C/C++函数库提供的,它的机制是很复杂的,例如为了分配一块内存,库函数会按照一定的算法(具体的算法可以参考数据结构/操作系统)在堆内存中搜索可用的足够大小的空间,如果没有足够大小的空间(可能是由于内存碎片太多),就有可能调用系统功能去增加程序数据段的内存空间,这样就有机会分 到足够大小的内存,然后进行返回。显然,堆的效率比栈要低得多。

            从这里我们可以看到,堆和栈相比,由于大量new/delete的使用,容易造成大量的内存碎片;由于没有专门的系统支持,效率很低;由于可能引发用户态和核心态的切换,内存的申请,代价变得更加昂贵。所以栈在程序中是应用最广泛的,就算是函数的调用也利用栈去完成,函数调用过程中的参数,返回地址, EBP(基址指针)和局部变量都采用栈的方式存放。所以,推荐尽量用栈,而不是用堆。

            无论是堆还是栈,都要防止越界现象的发生(除非你是故意使其越界),因为越界的结果要么是程序崩溃,要么是摧毁程序的堆、栈结构,产生以想不到的结果。

    new/delete与malloc/free详解

    malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符。它们都可用于申请和释放动态内存(堆)。

    C语言的函数malloc和free:
    1) 函数malloc和free在头文件<stdlib.h>中的原型及参数
    void * malloc(size_t size);
    动态配置内存,大小有size决定,返回值成功时为任意类型指针,失败时为NULL。

    void free(void *ptr);
    释放动态申请的内存空间,调用free()后ptr所指向的内存空间被收回,如果ptr指向未知地方或者指向的空间已被收回,则会发生不可预知的错误,如果ptr为NULL,free不会有任何作用。


    2) C语言中典型用法
    T为任意数据类型
    T * p = (T *) malloc (sizeof (T) * n)
    if (NULL= =p)
    {
    printf (“malloc fail!\n”);
    ……//相关资源收回的处理
    exit (-1);
    }
    … …//此过程不能改变指针p的指向
    free (p);
    注意:malloc后通常要对返回值进行判断,避免发生不必要的错误。


    3) 内存说明
    malloc函数动态申请的内存空间是在堆里(而一般局部变量存于栈里),并且该段内存不会被初始化,与全局变量不一样,如果不采用手动free()加以释放,则该段内存一直存在,直到程序退出才被系统,所以为了合理使用内存,在不适用该段内存时,应该调用free()。另外,如果在一个函数里面使用过malloc,最好要配对使用free,否则容易造成内存泄露。

    4) 不足
    对于非内部数据类型的对象而言,光用maloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free。


    C++中的运算符new和delete:
    new和delete是C++中的运算符,不是库函数,不需要库的支持,同时,他们是封装好的重载运算符,并且可以再次进行重载。
    1) 运算符new和delete
    new是动态分配内存的运算符,自动计算需要分配的空间,在C++中,它属于重载运算符,可以对多种数据类型形式进行分配内存空间,比如int型、char型、结构体型和类等的动态申请的内存分配,分配类的内存空间时,同时调用类的构造函数,对内存空间进行初始化,即完成类的初始化工作。

    delete是撤销动态申请的内存运算符。delete与new通常配对使用,与new的功能相反,可以对多种数据类型形式的内存进行撤销,包括类,撤销类的内存空间时,它要调用其析构函数,完成相应的清理工作,收回相应的内存资源。

    2) 典型用法

    • int *p = new int; delete p;
    • char *p = new char;delete p;
    • 类的类型 *p = new 类的类型;delete p;
    //注意,指针p存于栈中,p所指向的内存空间却是在堆中。
    • Obj * p = new Obj[100];delete [ ]p;
    //注意,new申请数组,delete删除的形式需要加括号“[ ]”,表示对数组空间的操作,总之,申请形式如何,释放的形式就如何。

    3) 内存说明
    new申请的内存也是存于堆中,所以在不需要使用时,需要delete手动收回。

    4) 动态内存的管理 
    删除( delete )指向动态分配内存的指针失败,因而无法将该块内存返还给自由存储区。删除动态分配内存失败称为“内存泄漏(memory leak)”。内存泄漏很难发现,一般需等应用程序运行了一段时间后,耗尽了所有内存空间时,内存泄漏才会显露出来。 
    读写已删除的对象。如果删除指针所指向的对象之后,将指针置为0值,则比较容易检测出这类错误。
    对同一个内存空间使用两次 delete 表达式。当两个指针指向同一个动态创建的对象,删除时就会发生错误。如果在其中一个指针上做 delete 运算,将该对象的内存空间返还给自由存储区,然后接着 delete 第二个指针, 此时则自由存储区可能会被破坏。
    操纵动态分配的内存时,很容易发生上述错误,但这些错误却难以跟踪和修正。

    new/delete与malloc/free之间的联系和区别:
    1) malloc/free和new/delete的联系
    • 存储方式相同。malloc和new动态申请的内存都位于堆中。申请的内存都不能自动被操作系统收回,都需要配套的free和delete来释放。
    • 除了带有构造函数和析构函数的类等数据类型以外,对于一般数据类型,如int、char等等,两组动态申请的方式可以通用,作用效果一样,只是形式不一样。
    • 内存泄漏对于malloc或者new都可以检查出来的,区别在于new可以指明是那个文件的那一行,而malloc没有这些信息。
    • 两组都需要配对使用,malloc配free,new配delete,注意,这不仅仅是习惯问题,如果不配对使用,容易造成内存泄露。同时,在C++中,两组之间不能混着用,虽说有时能编译过,但容易存在较大的隐患。
    • C++程序经常要调用C函数,而C程序只能用malloc/free管理动态内存

    2) malloc/free和new/delete的区别
    • malloc和free返回void类型指针,new和delete直接带具体类型的指针。new可以认为是malloc加构造函数的执行。
    • malloc和free属于C语言中的函数,需要库的支持,而new/delete是C++中的运算符,况且可以重载,所以new/delete的执行效率高些。C++中为了兼用C语法,所以保留malloc和free的使用,但建议尽量使用new和delete。
    在C++中,new是类型安全的,而malloc不是。例如:
    int* p = new char[10];  // 编译时指出错误
    delete [ ]p; //对数组需要加中括号“[ ]”
    int* p = malloc(sizeof(char )*10);  // 编译时无法指出错误
    free (p); //只需要所释放内存的头指针
    使用new动态申请类对象的内存空间时,类对象的构建要调用构造函数,相当于对内存空间进行了初始化。而malloc动态申请的类对象的内存空间时,不会初始化,也就是说申请的内存空间无法使用,因为类的初始化是由构造函数完成的。delete和free的意义分别于new和malloc相反,delete在释放堆空间之前会调用析构函数,而free函数则不会。
    • 不能用malloc和free来完成类对象的动态创建和删除。

    展开全文
  • 经过内存分配过程的准备阶段,我们分析到了Heap的AllocObjectWithAllocator()方法。 接下来我们将具体分析对象内存分配的过程。 ART对象分配过程解析——内存分配阶段 AllocObjectWithAllocator方法 首先我们来看...
  • C语言动态内存分配函数

    万次阅读 多人点赞 2019-06-02 23:46:57
    目录 1.malloc()2.free()3.calloc()4.realloc()5....所开辟的内存是在栈中开辟的固定大小的 ,如a是4字节 ,数组b是40字节 ,并且数组在申明时必须指定其长度 , 因为数组的内存是在编译时分配好的 . 如果我们想在...
  • 用if还是try catch来判断内存分配失败
  • 动态内存分配函数

    千次阅读 2018-03-28 21:43:28
    一、静态存储分配与动态存储分配: 二、动态内存分配函数 malloc calloc realloc free new delete
  • 动态内存分配

    2016-01-25 21:13:24
    malloc- 动态内存分配 void *malloc(size_t size); 向系统申请分配size个字节大小的内存空间。 如果分配成功,返回指向被分配内存的指针 calloc- 动态内存分配并清零 void *calloc(size_t n,siz
  • C语言动态内存分配

    2013-11-23 17:58:17
    C语言动态内存分配  动态数据结构可以在运行时灵活添加、删除或重排数据项。在运行时分配内存空间的过程称为动态内存分配内存分配函数如下: malloc 分配所需的字节大小,并返回指向所分配空间的第一个字节的...
  • C++内存分配方式、内存错误及其对策 内存分配方式有三种: 从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量。 在栈上创建。在执行...
  • ,包含在库函数 stdlib.h中,作用是在内存的堆区分配一个大小为size的连续空间,如果分配内存成功,函数返回新分配内存的首地址,否则,返回NULL,注意:鉴于上述这点,一般在写程序需要判断分配内存是否成功,如下...
  • C/C++内存分配管理

    万次阅读 多人点赞 2018-08-13 14:57:23
    内存分配及管理 1.内存分配方式 在C++中内存分为5个区,分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。 堆:堆是操作系统中的术语,是操作系统所维护的一块特殊内存,用于程序的内存动态分配,C语言...
  • C/C++ 动态内存分配

    万次阅读 多人点赞 2019-06-30 18:03:06
    首先我们看看 c 语言是如何进行动态内存分配的; c 语言主要是使用malloc / calloc / realloc 来进行内存申请的。 malloc / realloc / calloc三者的共同点与不同点: 共同点 1、都是从堆上进行动态内存分配 2、...
  • C++内存分配方式

    2014-03-04 11:03:12
    内存的三种分配方式: 1. 从静态存储区分配:此时的内存在...栈内存分配运算内置于处理器的指令集中,效率高,但容量有限。 3. 在堆区分配:动态分配内存。用new/malloc时开辟,delete/free时释放。生存期由用户指
  • 1.malloc函数的使用方法 : ...stdlib.h中,作用是在内存的堆区分配一个大小为size的连续空间,如果分配内存成功,函数返回新分配内存的首地址,否则,返回NULL,注意:鉴于上述这点,一般在写程序需要判断
  • C语言:内存分配

    2019-11-01 17:16:26
    一,内存分配 1,内存分配的类型: 在C/C++中内存分为5个区,分别为栈区、堆区、全局/静态存储区、常量存储区、代码区。 静态内存分配:编译时分配。包括:全局、静态全局、静态局部三种变量。 动态内存分配:运行...
  • malloc内存分配与free内存释放

    千次阅读 2016-09-04 16:56:23
    malloc不像全局变量一样,不是在编译器编译的时候就会分配内存空间,而是在调用到malloc函数时才会分配空间。有时还会中途调用free函数释放空间出来。所以:  1、malloc在第一次被调用时,从系统中获取最小为一...
  • 内存分配方式

    2010-10-13 16:29:00
    内存分配方式:(1)从静态存储区域分配。内存在程序编译时已经分配好,在程序运行期间都存在。...常见内存错误及解决办法:1、内存分配成功,却使用了它。 解决办法:在使用内存之前检查指针是否为NULL。如
  • C 内存分配

    千次阅读 2013-03-18 19:09:16
    C内存分配 程序代码区 存放函数体的二进制代码 全局数据区 全局变量和静态变量的存储是放在一起的。初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。常量...
  • malloc内存分配详解

    千次阅读 2015-09-21 16:57:57
    malloc不像全局变量一样,不是在编译器编译的时候就会分配内存空间,而是在调用到malloc函数时才会分配空间。有时还会中途调用free函数释放空间出来。所以:  1、malloc在第一次被调用时,从系统中获取最小为一...
  • c语言动态内存分配

    千次阅读 2019-01-03 23:00:21
    动态内存分配是许多高级程序设计技巧的关键。 所有程序都必须留下足够的内存来存储程序使用的数据。这些内存中,有些是自动分配的(栈),有些是在编译时就确定好的(静态区),c语言还可以实现动态的/运行时的内存...
  • Windows内存分配方式 Win32的堆分配函数 每一个进程都可以使用堆分配函数创建一个私有的堆──调用进程地址空间的一个或者多个页面。DLL创建的私有堆必定在调用DLL的进程的地址空间内,只能被调用进程访问。 ...
  • C++堆内存分配

    千次阅读 2017-03-30 08:42:46
    C++堆内存分配C堆内存分配 抽象与分层 如何扩展有效堆内存 brk和sbrk系统调用 如何维护有效堆内存 operator new抽象与分层​ c和c++的内存服务模型与计算机网络里面的协议分层模型有点类似。计算机网络协议大体分为...
  • C语言内存分配问题

    2012-12-04 20:55:52
    由编译器分配空间,在函数执行完由编译器自动释放。 堆:用来存放由动态分配函数(如malloc)分配的空间。是由程序员自己手动分配的,并且必须由程序员使用free释放。如果忘记用free释放,会导致所分配的空间一直...
  • 判断用new申请内存是否成功

    万次阅读 2014-07-04 10:24:23
    char* p=NULL;//最好初始化为NULL p = new char[nSize]; if(p == NULL) exit(); .... delete[] p; p = NULL; //删除马上赋值为NULL
  • linux内存管理总结之内存分配

    千次阅读 2014-09-26 17:17:36
     伙伴系统规定,无论是已分配内存块和空闲内存块,其大小都是2的k次幂个页面的大小,k的取值范围是0到MAX_ORDER 。当需要分配一个 大小为n个页面大小的内存块时,先计算一个i值,使2^i-1 ,然后在空闲内存块页面...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 158,453
精华内容 63,381
关键字:

内存分配后必须判断是否成功