程序设计中的内存思想(初学者)

    技术2022-05-20  35

    笨鸟先飞之我的学习日志NO.1

    --------内存分配

    程序设计中,明白内存的分配是至关重要的,下面仅是我作为一个初学者对自己阶段学习的一个小总结。如能得到各位大神们的指教,小弟将不胜感激!

    如果是32位的地址总线,寻址能力是232次方,刚好4G的内存,这里指的内存是虚拟内存。一个由c/c++程序占用的内存可以分为以下几个部分: 

     

    1)代码段  Text Segment          

    通常是指用来存放程序执行代码的一块内存区域。假如机器中有数个进程运行相同的一个程序,那么它们就可以使用同一个代码段。这部分区域的大小在程序运行前就已经确定,被只读保护起来,防止被错误的指令意外改写,在代码段中,也有可能包含一些只读的常数变量,例如字符串常量:char a[10]=hello!”等。所以又叫文字常量区,程序结束后由系统自动释放。

    2)数据段  Data Segment              

    通常是指用来存放程序中已初始化的全局变量和静态变量的一块内存区域(未初始化的全局变量和静态变量在相邻的另一块区域)。数据段属于静态内存分配。生存周期由程序结束后系统自动释放。如:由extern定义的全局变量,和在函数中由static定义的变量。

    3)堆(heap

    堆用于存放在进程中被程序员动态开辟的内存空间,他的大小不固定,由程序员定,可以扩张或缩减,当用malloc函数分配后,新的空间被加到堆上,利用Free函数时内存被释放,堆缩减。若程序员不释放,程序结束时可能由操作系统(OS)回收。注意它与数据结构中的堆不同,分配方式倒是类似于链表。堆是链式结构,他的生长方式是由低向高长。但是分配空间时:malloc510)在内存中找到与他最近的512bit,每次都有2bit没有用,这样多次调用后就会产生内存碎片!

    同时用mallocnew 分配了内存,就得用freedelete 释放,否则造成内存泄漏,但是只释放内存还是不够安全的,必须在释放内存后,让指针指向NULL,才不至于造成野指针。我理解的野指针就是没有正确指向的指针,他乱指。

     

     

    4)栈   stack

    由编译器自动分配,用于存放函数的参数值,局部变量的值等,也就是在函数{ }中定义的变量(但是不包括有static修饰的变量,因为他存放于数据段)。另外在函数调用时,其参数被压入引起调用的进程中,而且待到调用结束后,函数返回值也会被存放回栈中。由于他先进后出,由高向低生长特点,特别方便的用来保护/恢复调用现场,从这个角度看的话,我们可以把他理解成一个寄存,交换临时数据的内存区,程序运行结束后自动释放。 下面让我们用一个例子来理解上述区别:

    #include<stdio.h>

    #..........

    int a = 0; 全局初始化区

    char *p1; 全局未初始化区

    main()

    {

       int b; //,由编译器自动分配释放 ,存放函数的参数值,局部变量的值等

       char s[] = "abc";

       char *p2; ?

       char *p3 = "1234"; 1234/0在数据段(常量字符串)p3在栈上。

       static int c =0; 数据段(静态)初始化区

       p1 = (char *)malloc(10);

       p2 = (char *)malloc(20);//分配得来得1020字节的区域就在堆区。

       strcpy(p1, "1234"); // 1234/0放在常量区,编译器可能会将它与p3所指向的"1234"优化成一个地方。

    }

     

    下面对堆和栈的区别做个总结:

    1)分配和回收方式不同

    栈,是系统自动分配的,如在申明函数中的一个局部变量 int b 系统会在栈上自动为b开辟一个4个字节的空间,当函数结束系统后自动释放。

    堆,是人为分配的(malloc把节点放在堆里面存)必须指定大小,用完后必须由程序员Free释放。

    2)申请后系统的响应不同

    栈,只有当栈的剩余空间大于申请空间时,系统才分配内存,不然将报异常,提示栈溢出。

    堆,申请前要知道操作系统有一个记录空闲内存地址的链表,当系统收到申请时,会遍历该链表,需找到第一个空间大于所申请空间的堆节点,然后改节点删除,切断链,并将该节点的空间分配给程序。例外为了后面释放,一般会在这块空间的首地址处记录下分配空间的大小,如果找到堆的大小大于了申请大小,系统会自动把余下空间拉入新空闲链表中。

    3)大小的限制不同

    栈,在Windows, 是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,大小与操作系统有关,在32位电脑中默认1M 。如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。

    堆,堆的大小受限于计算机系统中有效的虚拟内存。(linux中为swap区)。

    4)数据结构不同

    栈,是一个连续空间顺序结构,栈是向低地址扩展的数据结构。

    堆,是链式结构。是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。由此可见,堆获得的空间比较灵活,也比较大。

    5)申请效率不同

    栈,由系统自动分配,速度较快(不是最快),但是程序员无法控制

    堆,是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便,好控制。

     

     

    小弟如今正在学习linux希望各位哥哥们多多指教!

     

     

     


    最新回复(0)