内存管理——常用函数接口

0.进程地址空间

 进程地址空间不是物理地址,是一种虚拟地址,由操作系统提供。进程地址空间本质是进程看待内存的方式,抽象出来的一个概念,内核中用一个结构体mm_struct表示,这样每个进程都认为自己独占系统内存资源。

在进程控制块task_struct中有一个mm_struct结构体指针,指向一个mm_struct结构体,这个结构体里面完成对各个数据区域的划分,然后通过页表映射到物理内存上。

1.用户空间

根据内存空间分配方式的不同,可以将内存分为动态内存静态内存。 

动态内存与静态内存是两种不同的分配内存的方式,那么它们在分配方式上存在什么样的区别呢?

  • 静态内存实际上是由编译器完成的、在栈空间的、按计划分配,其释放由作用域决定;
  • 动态内存是由程序员完成的、在堆空间的、按需分配,需要程序员手动释放。

计算机的内存空间都是通过指针进行访问的,而指针对于正确地分配动态内存空间来说又是十分重要的。关于动态内存的分配所使用的操作函数,在这里主要介绍malloc(),calloc(),realloc()和memset()函数的基本用法。

1.1 malloc()函数

函数原型:void* malloc(size_t size);

其中,size 参数是你希望分配的内存字节数。

  • 申请一块连续长度(虚拟内存连续)的内存空间,如果分配成功,malloc() 返回一个指向这块内存的指针。
  • 如果分配失败(例如,内存不足),malloc() 返回 NULL
  • 分配的内存区域在调用 free() 函数之前都是可用的,调用 free() 会释放该内存区域,使其可以被操作系统重新分配。

1.2 calloc()函数

函数原型:void* calloc(size_t num, size_t size);

其中,num 是你想要分配的元素的数量,size 是每个元素的大小(以字节为单位)。calloc() 会分配 num * size 字节的内存,并将这块内存的内容初始化为零。

  • 如果分配成功,calloc() 返回一个指向这块内存的指针。
  • 如果分配失败(例如,内存不足),calloc() 返回 NULL
  • 与 malloc() 一样,使用 calloc() 分配的内存区域需要通过调用 free() 函数来释放。

使用示例:

#include <stdio.h>  
#include <stdlib.h>  
  
int main() {  
    // 请求分配 10 个整数的空间,并初始化为零  
    int* numbers = (int*)calloc(10, sizeof(int));  
  
    if (numbers == NULL) {  
        printf("Memory allocation failed!\n");  
        return 1;  
    }  
  
    // 使用分配的内存  
    for (int i = 0; i < 10; i++) {  
        numbers[i] = i;  
    }  
  
    // 打印分配的内存中的内容  
    for (int i = 0; i < 10; i++) {  
        printf("%d ", numbers[i]);  
    }  
  
    // 释放内存  
    free(numbers);  
  
    return 0;  
}

1.3 realloc()函数

函数原型:void* realloc(void* ptr, size_t new_size);

realloc() 是 C 语言中用于重新分配之前已分配内存的函数。如果你已经使用 malloc() 或 calloc() 分配了一块内存,但后来发现这块内存不够大(或太大了),你可以使用 realloc() 来调整它的大小。

其中,ptr 是指向之前已分配内存的指针,new_size 是你想要的新内存大小(以字节为单位)。

  • 如果 new_size 大于原来的大小,realloc() 会尝试在原有内存之后扩展内存空间,并返回指向新内存区域的指针。
  • 如果 new_size 小于原来的大小,realloc() 会收缩内存区域,并可能移动内存块以释放多余的空间,同样返回指向新内存区域的指针。
  • 如果内存调整失败(例如,没有足够的内存来扩展),realloc() 返回 NULL,并且原来的内存块保持不变。

重要的是,如果 realloc() 成功,它可能会返回一个新的内存地址(即使大小没有变化)。因此,你总是应该使用 realloc() 的返回值来更新你的指针,而不是依赖原始的指针。

1.4 memset()函数

memset() 是 C 语言中的一个库函数,用于设置内存区域的内容。这个函数通常用于初始化内存区域,将其设置为一个特定的值。它的原型在 <string.h> 头文件中定义。

void *memset(void *ptr, int value, size_t num);

参数说明:

  • ptr:指向要设置的内存区域的指针。
  • value:要设置的值。这个值以 int 形式提供,但函数实际上按照 unsigned char 来解释它,并且只使用该值的低 8 位(即一个字节)。
  • num:要设置的字节数。

memset() 函数会将 ptr 指向的内存区域的前 num 个字节设置为 value 的低 8 位所表示的值。这意味着,如果 value 是一个整数,它将被解释为一个无符号字符,并且该字符值将被复制到内存区域的每个字节中。

2. 内核空间

2.1 kmalloc函数

2.2 kcalloc函数

2.3 krealloc函数

2.4 kfree函数

vmalloc/vfree

kmem_cache_create

__get_free_page/__get_free_pages

alloc_page/alloc_pages/free_pages

brk、sbrk

mmap/munmap

alloca

在开发板上编程测试这些函数的使用方法。理解记忆。

内存空间分布,每个区代表的意思,上述函数分别都是在哪个区申请的。

通过学习上述函数的内核代码实现,理解每个函数的特征及应用场景。

理解伙伴系统,理解页表,理解内存管理机制。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值