diff --git a/rt-thread-version/rt-thread-standard/programming-manual/memory/memory.md b/rt-thread-version/rt-thread-standard/programming-manual/memory/memory.md index 5e55d3c17e67c2fa784576880e69cb312bb132ee..439b37be6b4803aa57c8e7ad0c35b33f878385ce 100644 --- a/rt-thread-version/rt-thread-standard/programming-manual/memory/memory.md +++ b/rt-thread-version/rt-thread-standard/programming-manual/memory/memory.md @@ -178,14 +178,14 @@ rt_malloc 函数会从系统堆空间中找到合适大小的内存块,然后 |**参数** |**描述** | |------------------|------------------------------------| -| nbytes | 需要分配的内存块的大小,单位为字节 | +| nbytes | 需要分配的内存块的大小,单位为字节 (1B = 8 bit) | |**返回** | —— | | 分配的内存块地址 | 成功 | | RT_NULL | 失败 | 对 rt_malloc 的返回值进行判空是非常有必要的。应用程序使用完从内存分配器中申请的内存后,必须及时释放,否则会造成内存泄漏。 -使用动态分配内存示例: +##### 使用动态分配内存示例 ```c int *pi; @@ -210,10 +210,29 @@ rt_free 函数会把待释放的内存还回给堆管理器中。在调用这个 |----------|--------------------| | ptr | 待释放的内存块指针 | +```c +#include "rtthread.h" +/* +使用实例: + rt_free 的参数必须是以下其一: + - 是 NULL 。 - 是一个先前从 rt_malloc、 rt_calloc 或 rt_realloc 返回的值。 +*/ + +int main() +{ + + /* + 进行对ptr赋值,以null值为例子 + */ + int *ptr = RT_NULL; + /* 释放内存块指针 */ + rt_free(ptr); +} +``` #### 重分配内存块 在已分配内存块的基础上重新分配内存块的大小(增加或缩小),可以通过下面的函数接口完成: @@ -237,6 +256,92 @@ void *rt_realloc(void *rmem, rt_size_t newsize); - 如果原先的内存块无法改变大小,rt_realloc 将分配另一块正确大小的内存,并把原先那块内存的内容复制到新的块上。因此,在使用 rt_realloc 之后,你就不能再使用指向旧内存块的指针,而是应该改用 rt_realloc 所返回的新指针。 - 如果 rt_realloc 的第一个参数为 NULL, 那么它的行为就和 rt_malloc 一样。 +##### 使用重新分配内存的示例 + +```c +#include + +#define THREAD_PRIORITY 25 +#define THREAD_STACK_SIZE 512 +#define THREAD_TIMESLICE 5 + +int exsample_realloc(void) +{ + /* 初始分配的元素数量和每个元素的大小 */ + rt_size_t initial_count = 5; + rt_size_t new_count = 10; + rt_size_t size = sizeof(int); + + /* 分配初始内存 */ + void *ptr = rt_malloc(initial_count * size); + if (ptr == RT_NULL) { + rt_kprintf("Initial memory allocation failed.\n"); + return -1; + } + + /* 将指针强制转换为 int 类型指针 */ + int *intArray = (int *)ptr; + + /* 使用初始分配的内存 */ + for (int i = 0; i < initial_count; i++) { + intArray[i] = i * 10; + } + + /* 打印初始分配的内存内容 */ + rt_kprintf("Initial allocated memory contents:\n"); + for (int i = 0; i < initial_count; i++) { + rt_kprintf("%d ", intArray[i]); + } + rt_kprintf("\n"); + + /* 重新分配内存 */ + ptr = rt_realloc(ptr, new_count * size); + if (ptr == RT_NULL) { + rt_kprintf("Re-allocation failed.\n"); + rt_free(intArray); + return -1; + } + + /* 更新指针 */ + intArray = (int *)ptr; + + /* 使用重新分配后的内存 */ + for (int i = initial_count; i < new_count; i++) { + intArray[i] = i * 10; + } + + /* 打印重新分配后的内存内容 */ + rt_kprintf("Re-allocated memory contents:\n"); + for (int i = 0; i < new_count; i++) { + rt_kprintf("%d ", intArray[i]); + } + rt_kprintf("\n"); + + /* 释放内存 */ + rt_free(ptr); + + return 0; +} + + +int rt_realloc_sample(void) +{ + rt_thread_t tid = RT_NULL; + + /* 创建线程 1 */ + tid = rt_thread_create("thread1", + exsample_realloc, RT_NULL, + THREAD_STACK_SIZE, + THREAD_PRIORITY, + THREAD_TIMESLICE); + if (tid != RT_NULL) + rt_thread_startup(tid); + + return 0; +} +/* 导出到 msh 命令列表中 */ +MSH_CMD_EXPORT(rt_realloc_sample, rt_readlloc_sample); +``` #### 分配多内存块 从内存堆中分配连续内存地址的多个内存块,可以通过下面的函数接口完成: @@ -257,6 +362,67 @@ void *rt_realloc(void *rmem, rt_size_t newsize); | 指向第一个内存块地址的指针 | 成功 ,并且所有分配的内存块都被初始化成零。 | | RT_NULL | 分配失败 | +##### 使用分配多内存块示例 + +```c +#include + +#define THREAD_PRIORITY 25 +#define THREAD_STACK_SIZE 512 +#define THREAD_TIMESLICE 5 + +int exsample_calloc(void) +{ + /* 定义要分配的元素数量和每个元素的大小 */ + rt_size_t count = 5; + rt_size_t size = sizeof(int); + + /* 分配内存 */ + void *ptr = rt_calloc(count, size); + if (ptr == RT_NULL) { + rt_kprintf("Memory allocation failed.\n"); + return -1; + } + + /* 将指针强制转换为 int 类型指针 */ + int *intArray = (int *)ptr; + + /* 使用分配的内存 */ + for (int i = 0; i < count; i++) { + intArray[i] = i * 10; + } + + /* 打印分配的内存内容 */ + rt_kprintf("Allocated memory contents:\n"); + for (int i = 0; i < count; i++) { + rt_kprintf("%d ", intArray[i]); + } + rt_kprintf("\n"); + + /* 释放内存 */ + rt_free(ptr); + + return 0; +} + +int rt_calloc_sample(void) +{ + rt_thread_t tid = RT_NULL; + + /* 创建线程 1 */ + tid = rt_thread_create("thread1", + exsample_calloc, RT_NULL, + THREAD_STACK_SIZE, + THREAD_PRIORITY, + THREAD_TIMESLICE); + if (tid != RT_NULL) + rt_thread_startup(tid); + + return 0; +} +/* 导出到 msh 命令列表中 */ +MSH_CMD_EXPORT(rt_calloc_sample, rt_calloc sample); +``` #### 设置内存钩子函数 在分配内存块过程中,用户可设置一个钩子函数,调用的函数接口如下: @@ -316,6 +482,116 @@ void hook(void *ptr); |----------|--------------------| | ptr | 待释放的内存块指针 | +##### 内存钩子函数示例 + +```c +#include + +#define THREAD_PRIORITY 25 +#define THREAD_STACK_SIZE 512 +#define THREAD_TIMESLICE 5 + +/* 定义内存钩子函数 */ +void malloc_hook(void *ptr, rt_size_t size) +{ + rt_kprintf("malloc: %p, size: %ld\n", ptr, size); +} + +void free_hook(void *ptr) +{ + rt_kprintf("free: %p\n", ptr); +} + +/* 注册内存钩子函数 */ +void register_memory_hooks() +{ + rt_malloc_sethook(malloc_hook); + rt_free_sethook(free_hook); +} + +/* 初始分配的元素数量和每个元素的大小 */ +rt_size_t initial_count = 5; +rt_size_t new_count = 10; +rt_size_t size = sizeof(int); + +/* 内存操作函数 */ +int exsample_realloc(void) +{ + /* 分配初始内存 */ + void *ptr = rt_malloc(initial_count * size); + if (ptr == RT_NULL) { + rt_kprintf("Initial memory allocation failed.\n"); + return -1; + } + + /* 将指针强制转换为 int 类型指针 */ + int *intArray = (int *)ptr; + + /* 使用初始分配的内存 */ + for (int i = 0; i < initial_count; i++) { + intArray[i] = i * 10; + } + + /* 打印初始分配的内存内容 */ + rt_kprintf("Initial allocated memory contents:\n"); + for (int i = 0; i < initial_count; i++) { + rt_kprintf("%d ", intArray[i]); + } + rt_kprintf("\n"); + + /* 重新分配内存 */ + ptr = rt_realloc(ptr, new_count * size); + if (ptr == RT_NULL) { + rt_kprintf("Re-allocation failed.\n"); + rt_free(intArray); + return -1; + } + + /* 更新指针 */ + intArray = (int *)ptr; + + /* 使用重新分配后的内存 */ + for (int i = initial_count; i < new_count; i++) { + /* 给新扩展的元素赋值 */ + intArray[i] = i * 10; + } + + /* 打印重新分配后的内存内容 */ + rt_kprintf("Re-allocated memory contents:\n"); + for (int i = 0; i < new_count; i++) { + rt_kprintf("%d ", intArray[i]); + } + rt_kprintf("\n"); + + /* 释放内存 */ + rt_free(ptr); + + return 0; +} + +int rt_memory_hook_sample(void) +{ + rt_thread_t tid = RT_NULL; + + /* 注册内存钩子函数 */ + register_memory_hooks(); + + /* 创建线程 */ + tid = rt_thread_create("thread1", + exsample_realloc, RT_NULL, + THREAD_STACK_SIZE, + THREAD_PRIORITY, + THREAD_TIMESLICE); + if (tid != RT_NULL) + rt_thread_startup(tid); + + return 0; +} + +/* 导出到 msh 命令列表中 */ +MSH_CMD_EXPORT(rt_memory_hook_sample, rt_memory_hook_sample); +``` + ### 总结 动态内存使用总结: @@ -353,7 +629,9 @@ void hook(void *ptr); void thread1_entry(void *parameter) { int i; - char *ptr = RT_NULL; /* 内存块的指针 */ + /* 内存块的指针 */ + char *ptr = RT_NULL; + /* 内存块的指针 */ for (i = 0; ; i++) { @@ -363,14 +641,28 @@ void thread1_entry(void *parameter) /* 如果分配成功 */ if (ptr != RT_NULL) { + /* + *此处是以1往左移位,因此,内存块大小为2的指数次方 + *2进制 10进制 + *0001 1 + *0010 2 + *0100 4 + *1000 8 + *..... + *1 << n 2^n + */ rt_kprintf("get memory :%d byte\n", (1 << i)); - /* 释放内存块 */ + + /* 释放内存块,及时释放内存块,避免导致内存泄漏 */ rt_free(ptr); rt_kprintf("free memory :%d byte\n", (1 << i)); + + /* 将指针置空 */ ptr = RT_NULL; } else { + /* 若申请内存失败则进行退出,并告知目前无法申请的内存大小 */ rt_kprintf("try to get %d byte memory failed!\n", (1 << i)); return; }