07_内存管理

1 内存管理方式

1.1 虚拟内存空间认识

        在嵌入式程序设计中,程序的允许基于特点的嵌入式系统允许,比如使用的Linux系统。

在Linux系统中,程序的允许会创建一个进程,对于进程是资源管理的最小单位。在32位的系统中,每一个进程的允许都会创建一个虚拟的4G内存空间:地址序号介于:0x0 ~ 0xffff ffff。

1.2 内存空间的分配方式

        对于虚拟内存空间的分配,主要包含两种方式:分别为静态内存分配和动态内存分配。

1.2.1 静态内存分配

        所谓的静态内存分配,指的是所分配的内存空间,是在程序运行过程中实现空间的自动开辟和释放,空间的生命周期和大小是固定。

  1. 在程序运行的时候,按照事先约定的大小来进行空间的大小的管理。
  2. 静态内存空间:存储的是局部变量以及全局变量
  3. 静态内存空间:主要包含的是静态存储区和栈区数据。

1.2.2 动态内存分配

        所谓的动态内存分配,指的是所分配的内存空间,是在程序运行过程中按照设计者的需求手段开辟和释放,空间的生命周期和大小都是由设用者决定。

  1. 在程序运行的时候,按照程序者设定的大小管理(根据使用者数据量的大小来分配空间)。
  2. 动态内存空间:使用指针管理,存储在堆区。

2 动态内存管理

2.1 动态内存开辟和释放的API

#include <stdlib.h>
void *malloc(size_t size);
功能:动态开辟指定字节数的内存空间
参数:
    size表示需要开辟空间的字节数;
        一般使用大于0的值,表示开辟指定字节大小的内存空间,成功返回所开辟的内存空间的起始地址,内存空间的数据未做初始化设置;
        可以设置为0值,可能会NULL;返回一个地址值但是指向的空间不能访问,只能用free释放空间。
返回值:成功返回内存空间的起始地址,失败返回NULL。   
                                             
void free(void *ptr);
功能:用来动态释放由malloc、calloc和realloc动态开辟的存储空间。
参数:ptr表示动态内存空间的起始地址
    释放的是ptr指向内存空间的信息:所开辟的存储空间以及内存的相关信息。
注意:在内存空间释放之后,需要将指针值设置为NULL,在对内存访问的时候,可以运用指针的指针判断内存空间是否已经释放:
    1) 如果ptr==NULL,说明内存空间已经释放;不能继续通过指针访问;
    2) 如果ptr!=NULL,说明内存空间未释放,可以继续访问。 
 
void *calloc(size_t nmemb, size_t size);
参数:动态开辟指定元素空间的大小和元素个数的内存空间
参数:
    参数1:nmemb表示的需要存储元素的个数;
    参数2:size表示每一个元素所占空间的字节数。
        功能等价于:malloc(nmemn*size);
返回值:成功返回开辟内存空间的起始地址,失败返回NULL。
                
void *realloc(void *ptr, size_t size);
功能:改变ptr指向内存空间的大小
参数:
    参数1:ptr已开辟动态存储空间的起始地址,
    参数2:size表示新动态存储空间的大小
        1) size <= ptr指向原有开辟内存空间的大小,对原有空间裁剪得到新的内存空间。
            新内存空间的起始地址等于原来内存空间的起始地址并返回,多出来的部分空间会自动释放。
        2) size > ptr指向原有开辟内存空间的大小:会根据后面空闲空间的大小决定
            如果在原有开辟内存空间之后,有为被开辟使用的空闲内存空间,且size < ptr指向原有空间的大小+空闲空间的大小
                在原有开辟内存空间之后追加开辟内存空间,并返回原有开辟内存空间的起始地址。
            否则:重新找空间开辟,并将原有空间的数据拷贝到新开辟的空间中,还会自动释放原有开辟的空间。
返回值:成功返回新开辟空间的起始地址。失败返回NULL

2.2 内存管理函数实例

        1.malloc、calloc函数实例

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



int main()
{
        char *p; 

        printf("p:%p\n", p); 
        p = malloc(32);    /* 动态开辟32字节的存储空间 */
        if (p == NULL) {
                perror("malloc error");
                return -1; 
        }
        printf("p:%p\n", p); 

        strcpy(p, "hello test");    /* 将字符串数据拷贝到堆区空间中 */
        printf("p : %s\n", p); 

        free(p);    /* 释放堆区空间 */
        p = NULL;
        if (p == NULL) {
                p = calloc(16,1);    /* 动态开辟存储16个元素,每个元素空间为1字节的存储空间 */
                if (p == NULL) {
                        perror("calloc error");
                        return -1;
                }
                printf("p:%p\n", p);
        }
        *p = 'A';
        printf("p : %s\n", p);
        free(p);    /* 释放空间 */
        p = NULL;

        return 0;
}

2.realloc函数实例

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



int main()
{
        char *p; 

        printf("p:%p\n", p); 
        p = malloc(32);    /* 动态开辟32字节空间 */
        if (p == NULL) {
                perror("malloc error");
                return -1; 
        }   
        printf("p:%p\n", p); 

        p = realloc(p, 64);    /* 改变空间的大小 */
        printf("p:%p\n", p); 

        free(p);    /* 释放空间 */
        p = NULL;
}

2.3 内存泄漏

        所谓的内存泄露(Memory Leak),指的是在程序中动态开辟的内存空间,因为指针的修改或者其它原因在程序结束的时候,对应的空间未做释放,此时导致内存泄漏。会影响系统中其它程序的正常运行,主要导致程序运行效率降低,可能会出现程序的卡顿或者死机等现象。

        在程序设计过程中,需要尽可能的避免内存泄漏。

1) 在对于动态内存指针的访问结束的时候,需要注意指针指向的内存空间是否调用free做内存释放。

2) 可以内存资源的检索,找到已内存泄漏地址空间,对其进行内存释放。

3) 程序结束系统重启,会自动做内存资源的回收。

3 内存分布图

是一个基本内存分布图,其中实际应用过程会有一定调整:

  1. 堆区和栈区没有固定的分隔解析,是可变的。
  2. 在内核空间和栈区空间之间,包含到环境变量存储区。存储系统运行的环境变量
  3. 内存分布实例:
#include <stdio.h>
#include <stdlib.h>

int data_a = 123;
int bss_a;
int data_b = 123;
int bss_b;

void test()
{

}

int main()
{
        int *p = malloc(2);
        /* 输出的函数的地址 */
        printf("test : %p\n", test);
        printf("main : %p\n", main);

        /* 输出数据常量的地址 */
        printf("%p\n", "1234567890");

        /* 输出.data段的地址 */
        printf("&data_a : %p\n", &data_a);
        printf("&data_b : %p\n", &data_b);、
        /* 输出.bss段的地址 */
        printf("&bss_a : %p\n", &bss_a);
        printf("&bss_b : %p\n", &bss_b);
        /* 输出堆区地址 */
        printf("p: %p\n", p);
        /* 输出栈区地址 */
        printf("&p : %p\n", &p);
        free(p);
        p = NULL;
}

通过输出结果发现:地址值逐一递增。

对于.data和.bss的区别,前者编译好的程序空间更大。

  • 19
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值