• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 物理内存管理
2
3
4## 基本概念
5
6物理内存是计算机上最重要的资源之一,指的是实际的内存设备提供的、可以通过CPU总线直接进行寻址的内存空间,其主要作用是为操作系统及程序提供临时存储空间。LiteOS-A内核管理物理内存是通过分页实现的,除了内核堆占用的一部分内存外,其余可用内存均以4KiB为单位划分成页帧,内存分配和内存回收便是以页帧为单位进行操作。内核采用伙伴算法管理空闲页面,可以降低一定的内存碎片率,提高内存分配和释放的效率,但是一个很小的块往往也会阻塞一个大块的合并,导致不能分配较大的内存块。
7
8
9## 运行机制
10
11如下图所示,LiteOS-A内核的物理内存使用分布视图,主要由内核镜像、内核堆及物理页组成。内核堆部分见堆内存管理一节。
12
13  **图1** 物理内存使用分布图
14
15  ![zh-cn_image_0000001222655518](figures/zh-cn_image_0000001222655518.png)
16
17伙伴算法把所有空闲页帧分成9个内存块组,每组中内存块包含2的幂次方个页帧,例如:第0组的内存块包含2的0次方个页帧,即1个页帧;第8组的内存块包含2的8次方个页帧,即256个页帧。相同大小的内存块挂在同一个链表上进行管理。
18
19- 申请内存
20  系统申请12KiB内存,即3个页帧时,9个内存块组中索引为3的链表挂着一块大小为8个页帧的内存块满足要求,分配出12KiB内存后还剩余20KiB内存,即5个页帧,将5个页帧分成2的幂次方之和,即4跟1,尝试查找伙伴进行合并。4个页帧的内存块没有伙伴则直接插到索引为2的链表上,继续查找1个页帧的内存块是否有伙伴,索引为0的链表上此时有1个,如果两个内存块地址连续则进行合并,并将内存块挂到索引为1的链表上,否则不做处理。
21
22    **图2** 内存申请示意图
23
24    ![zh-cn_image_0000001189778871](figures/zh-cn_image_0000001189778871.png)
25
26- 释放内存
27  系统释放12KiB内存,即3个页帧,将3个页帧分成2的幂次方之和,即2跟1,尝试查找伙伴进行合并,索引为1的链表上有1个内存块,若地址连续则合并,并将合并后的内存块挂到索引为2的链表上,索引为0的链表上此时也有1个,如果地址连续则进行合并,并将合并后的内存块挂到索引为1的链表上,此时继续判断是否有伙伴,重复上述操作。
28
29    **图3** 内存释放示意图
30
31    ![zh-cn_image_0000001143739220](figures/zh-cn_image_0000001143739220.png)
32
33
34## 开发指导
35
36
37### 接口说明
38
39  **表1** 物理内存管理模块接口
40
41| 功能分类 | 接口描述 |
42| -------- | -------- |
43| 申请物理内存 | -&nbsp;LOS_PhysPageAlloc:申请一个物理页<br/>-&nbsp;LOS_PhysPagesAlloc:申请物理页并挂在对应的链表上<br/>-&nbsp;LOS_PhysPagesAllocContiguous:申请多页地址连续的物理内存 |
44| 释放物理内存 | -&nbsp;LOS_PhysPageFree:释放一个物理页<br/>-&nbsp;LOS_PhysPagesFree:释放挂在链表上的物理页<br/>-&nbsp;LOS_PhysPagesFreeContiguous:释放多页地址连续的物理内存 |
45| 查询地址 | -&nbsp;LOS_VmPageGet:根据物理地址获取其对应的物理页结构体指针<br/>-&nbsp;LOS_PaddrToKVaddr:根据物理地址获取其对应的内核虚拟地址 |
46
47
48### 开发流程
49
50内存申请时根据需要调用相关接口,小内存申请建议使用堆内存申请相关接口,4KiB及以上内存申请可以使用上述物理内存相关接口。
51
52> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
53> - 物理内存申请相关接口需要在OsSysMemInit接口完成初始化之后再使用;
54>
55> - 内存申请的基本单位是页帧,即4KiB;
56>
57> - 物理内存申请时,有地址连续要求的使用LOS_PhysPagesAllocContiguous接口,无地址连续的要求尽量使用LOS_PhysPagesAlloc接口,将连续的大块内存留给有需要的模块使用。
58
59
60### 编程实例
61
62编程示例主要是调用申请、释放接口对内存进行操作,包括申请一个页以及多个页的示例。
63
64
65```
66#include "los_vm_phys.h"
67
68#define PHYS_PAGE_SIZE 0x4000
69
70// 申请一个页
71VOID OsPhysPagesAllocTest3(VOID)
72{
73    PADDR_T newPaddr;
74    VOID *kvaddr = NULL;
75    LosVmPage *newPage = NULL;
76
77    newPage = LOS_PhysPageAlloc();
78    if (newPage == NULL) {
79        printf("LOS_PhysPageAlloc fail\n");
80        return;
81    }
82    printf("LOS_PhysPageAlloc success\n");
83
84    newPaddr = VM_PAGE_TO_PHYS(newPage);
85    kvaddr = OsVmPageToVaddr(newPage);
86
87    // Handle the physical memory
88
89    // Free the physical memory
90    LOS_PhysPageFree(newPage);
91}
92
93// 申请多个页,不要求连续
94VOID OsPhysPagesAllocTest2(VOID)
95{
96    UINT32 sizeCount;
97    UINT32 count;
98    UINT32 size = PHYS_PAGE_SIZE;
99    LosVmPage *vmPageArray[PHYS_PAGE_SIZE >> PAGE_SHIFT] = { NULL };
100    UINT32 i = 0;
101    LosVmPage *vmPage = NULL;
102    PADDR_T pa;
103
104    size = LOS_Align(size, PAGE_SIZE);
105    if (size == 0) {
106        return;
107    }
108    sizeCount = size >> PAGE_SHIFT;
109
110    LOS_DL_LIST_HEAD(pageList);
111
112    count = LOS_PhysPagesAlloc(sizeCount, &pageList);
113    if (count < sizeCount) {
114        printf("failed to allocate enough pages (ask %zu, got %zu)\n", sizeCount, count);
115        goto ERROR;
116    }
117    printf("LOS_PhysPagesAlloc success\n");
118    while ((vmPage = LOS_ListRemoveHeadType(&pageList, LosVmPage, node))) {
119        pa = vmPage->physAddr;
120        vmPageArray[i++] = vmPage;
121        // Handle the physical memory
122    }
123
124    // Free the physical memory
125    for (i = 0; i < sizeCount; ++i) {
126        LOS_PhysPageFree(vmPageArray[i]);
127    }
128
129    return;
130
131ERROR:
132    (VOID)LOS_PhysPagesFree(&pageList);
133}
134
135// 申请多个连续页
136VOID OsPhysPagesAllocTest1(VOID)
137{
138    VOID *ptr = NULL;
139    LosVmPage *page = NULL;
140    UINT32 size = PHYS_PAGE_SIZE;
141
142    ptr = LOS_PhysPagesAllocContiguous(ROUNDUP(size, PAGE_SIZE) >> PAGE_SHIFT);
143    if (ptr == NULL) {
144        printf("LOS_PhysPagesAllocContiguous fail\n");
145        return;
146    }
147
148    printf("LOS_PhysPagesAllocContiguous success\n");
149
150    // Handle the physical memory
151
152    // Free the physical memory
153    page = OsVmVaddrToPage((VOID *)ptr);
154    LOS_PhysPagesFreeContiguous((VOID *)ptr, size >> PAGE_SHIFT);
155}
156
157UINT32 ExamplePhyMemCaseEntry(VOID)
158{
159    OsPhysPagesAllocTest1();
160    OsPhysPagesAllocTest2();
161    OsPhysPagesAllocTest3();
162    return LOS_OK;
163}
164```
165
166
167### 结果验证
168
169编译运行得到的结果为:
170
171
172```
173LOS_PhysPagesAllocContiguous success
174LOS_PhysPagesAlloc success
175LOS_PhysPageAlloc success
176```
177