C语言精讲之程序中内存从哪里来(3)堆

  • Post author:
  • Post category:其他



C语言精讲之程序中内存从哪里来(1)内存



C语言精讲之程序中内存从哪里来(2)栈



C语言精讲之程序中内存从哪里来(3)堆



C语言精讲之程序中内存从哪里来(4)数据段


3、堆


一、

堆具有操作系统堆管理器管理、大块内存、程序手动申请&释放、脏内存、临时性

(1)、

操作系统堆管理器管理


堆管理是操作系统的一个模块,堆管理内存分配灵活,按需分配。

(2)、

大块内存


堆内存管理者总量很大的操作系统内存块,各进程可以按需申请使用,使用完释放。

比如

:图书馆借书,你根据自己的需求,借相应的书籍,向图书馆申请,这期间别人借不了,等你使用完之后,再申请还书。

(3)、

程序手动申请&释放


手工的意思是需要写代码去申请malloc(或者相似malloc族)和释放内存free。

(4)、

脏内存


堆内存也是反复使用的,而且使用者用完释放前不会清除,因此也是脏内存。

比如

:一个人申请一个酒店房间以后,用完没有打扫,当下一个人使用的适合,酒店直接诶这个人分配了这个房间,而没有进行打扫,当这个人使用的时候就是脏的。

(5)、

临时性


堆内存只在malloc的free之间属于这个进程,而可以访问,在malloc之前和free之后都不能访问,否则会有不可预料的后果。


二、

堆内存使用范例

4.5.2.2、堆内存使用范例

(1)、原型 void *malloc(size_t size)

1)void *是一个指针类型,malloc返回的是一个void *类型的指针,实质上malloc返回的是堆管理器分配给我本次申请的那段内存空间的首地址(malloc返回的值其实是一个数字,这个数字表示一个内存地址)。

2)为什么要使用void *作为类型?主要原因是malloc()帮我们分配内存是只是分配内存空间,至于这段空间用来做存储什么类型的元素malloc是不关心的,由我们程序来自己决定。

(2)、什么是void类型。早期被翻译成空型,这个翻译不好,会误导人,void类型不表示没有类型,而是表示万能类型。void的意思就是这个数据的类型当前是不确定的,在需要的时候可以强制转换成其它任何一种确定类型的指针,也就是说这个指针可以指向任何类型的元素。通过头指针来访问malloc的数据。

(3)、malloc的返回值:成功申请空间后返回这个空间的指针,申请失败返回NULL。所以malloc后的内存指针一定要先检验是否为NULL。

(4)、malloc使用完之后一定要free释放,free(p);会告诉堆管理器这段内存我用完你可以回收了,堆管理器回收这段内存后,这段内存就不应该再去使用这段内存,因为释放后堆管理器就可能把这段内存分配给其它的进程,所以不应该再使用这段内存。

(5)、在调用free()归还这段内存之前,指向这段内存的指针P一定不能丢(也就是不能给P赋值)因为 一旦p丢失,malloc的这一段内存就消失了(内存泄漏),直到当前程序结束时操作系统才会回收这段内存。


三、

malloc的一些细节表现

(1)、

malloc(0)


malloc申请0个字节一般不会碰到这个需求,因为本来申请内存就是拿来用的。

如果真的malloc(0),返回的还是一个有效的指针吗?

答案是:实际上分配了32位机(0x10)16byte( 1B(byte,字节)= 8 bit)的一段内存并返回了这段内存的地址。这个答案并不是固定的,因为C语言并没有明确规定malloc(0)时的表现,由各malloc函数库的实现者来定义(也就是具体分配多少并不是统一的)

(2)、

malloc(4)


gcc中的malloc默认最小以16B(32位机)为分配单位,如果malloc小于16B的大小都会返回一个32字节的大小的内存,malloc实现时没有按照自己的分配而是允许一些的块内存的分配。(相当于规定了一个个大小不同的块内存,比如需要二分之一的方便面,人家只会卖给你一包)

(3)、

malloc(20)去访问第25、第250、第2500。。。会怎么样?


实战中:120字节处正确,1200字节处正确…往后继续访问总有一个数据会发生段错误,所以申请多少就应该用多少。不要去使用没有申请的内存,这不是一个好的习惯。

#include <stdio.h>
#include  <stdlib.h>

//需要一个1000个int类型的元素数组
int main()
{
    //第一步:申请和绑定
    int *p=(int *)malloc(1000*sizeof(int));

    //第二步:检验是否分配成功
    if(NULL == p)
    {
        printf("malloc error\n");
        return -1;
    }

    //第三步:使用申请到的内存

    //p = &a;     //如果在free之前给P另外赋值,那么malloc申请的那段内存就丢失掉了
                //malloc后P和返回的内存相绑定,P是那段内存在当前进程的唯一联系人,
                //相当于唯一一把钥匙
                //如果P没有free之前就丢了,这段内存就永远丢点了,
                //丢了的概念就是在操作系统中这段内存是当前进程拿着的,但是用不了
                //所以你想申请新的内存来替换使用,这就是叫做程序“吃内存”,叫内存泄漏

       *(p+0)=1;
       *(p+1)=2;
       printf("*(p+0)=%d\n",*(p+0));
       printf("*(p+1)=%d\n",*(p+1));

    //第四步:释放内存
    free(p);
    p=NULL;
}



版权声明:本文为qq_43706089原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。