更新日期: 2022/06/01 来源: https://gitee.com/weharmony/kernel_liteos_a_note
oom.c
浏览该文件的文档.
1/*
2 * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
3 * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this list of
9 * conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
12 * of conditions and the following disclaimer in the documentation and/or other materials
13 * provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
16 * to endorse or promote products derived from this software without specific prior written
17 * permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include "los_oom.h"
33#include "los_init.h"
34#include "los_vm_dump.h"
35#include "los_vm_lock.h"
36#include "los_vm_phys.h"
37#include "los_vm_filemap.h"
38#include "los_process_pri.h"
39#ifdef LOSCFG_BASE_CORE_SWTMR_ENABLE
40#include "los_swtmr_pri.h"
41#endif
42
43#ifdef LOSCFG_FS_VFS
44#include "console.h"
45#endif
46
47
48#ifdef LOSCFG_KERNEL_VM
49
50LITE_OS_SEC_BSS OomCB *g_oomCB = NULL; //全局内存溢出控制块
51static SPIN_LOCK_INIT(g_oomSpinLock);//内存溢出自旋锁
52
53LITE_OS_SEC_TEXT_MINOR STATIC UINT32 OomScoreProcess(LosProcessCB *candidateProcess)
54{
55 UINT32 actualPm;
56
57#ifndef LOSCFG_KERNEL_SMP
58 (VOID)LOS_MuxAcquire(&candidateProcess->vmSpace->regionMux);
59#endif
60 /* we only consider actual physical memory here. */ //只考虑实际的物理内存
61 OsUProcessPmUsage(candidateProcess->vmSpace, NULL, &actualPm);
62#ifndef LOSCFG_KERNEL_SMP
63 (VOID)LOS_MuxRelease(&candidateProcess->vmSpace->regionMux);
64#endif
65 return actualPm;
66}
67///用于设置 g_oomCB->processVictimCB 回调函数
68LITE_OS_SEC_TEXT_MINOR STATIC UINT32 OomKillProcess(UINTPTR param)
69{
70 /* we will not kill process, and do nothing here */
71 return LOS_OK;
72}
73///强制收缩内存
74LITE_OS_SEC_TEXT_MINOR STATIC UINT32 OomForceShrinkMemory(VOID)
75{
76 UINT32 i;
77 UINT32 reclaimMemPages = 0;
78
79 /*
80 * TryShrinkMemory maybe reclaim 0 pages in the first time from active list
81 * to inactive list, and in the second time reclaim memory from inactive list.
82 */
83 //TryShrinkMemory可能会在第一时间从活动列表中回收0页到非活动列表,并在第二次从非活动列表中回收内存。
84 for (i = 0; i < MAX_SHRINK_PAGECACHE_TRY; i++) {
85 reclaimMemPages += OsTryShrinkMemory(0);
86 }
87
88 return reclaimMemPages;
89}
90///内存不足时回收页高速缓存
91LITE_OS_SEC_TEXT_MINOR STATIC BOOL OomReclaimPageCache(VOID)
92{
93 UINT32 totalPm = 0;
94 UINT32 usedPm = 0;
95 BOOL isReclaimMemory = FALSE;
96 UINT32 reclaimMemPages;
97 UINT32 i;
98
99 for (i = 0; i < MAX_SHRINK_PAGECACHE_TRY; i++) {
100 OsVmPhysUsedInfoGet(&usedPm, &totalPm);//获取总的和已经使用的物理内存数量
101 isReclaimMemory = ((totalPm - usedPm) << PAGE_SHIFT) < g_oomCB->reclaimMemThreshold;//检查是否过了回收门槛
102 if (isReclaimMemory) {//要回收了
103 /*
104 * we do force memory reclaim from page cache here.
105 * if we get memory, we will reclaim pagecache memory again.
106 * if there is no memory to reclaim, we will return.
107 */
108 //在这里强制从页缓存中回收内存,
109 reclaimMemPages = OomForceShrinkMemory();//强制回收内存
110 if (reclaimMemPages > 0) {//如果得到内存,将再次回收pagecache内存
111 continue;
112 }
113 }
114 break;//实在没有内存可回收
115 }
116
117 return isReclaimMemory;//返回回收的数量
118}
119
120/*
121 * check is low memory or not, if low memory, try to kill process.
122 * return is kill process or not.
123 */
124LITE_OS_SEC_TEXT_MINOR BOOL OomCheckProcess(VOID)//检查内存是否不足,如果内存不足,请尝试终止进程,返回是否kill进程
125{
126 UINT32 totalPm;
127 UINT32 usedPm;
128 BOOL isLowMemory = FALSE;
129
130 /*
131 * spinlock the current core schedule, make sure oom process atomic //旋转锁定当前核心计划,确保oom进程原子化
132 * spinlock other place entering OomCheckProcess, make sure oom process mutex //旋转锁定其他进入OomCheckProcess的地方,确保oom进程互斥
133 */
134 LOS_SpinLock(&g_oomSpinLock);
135
136 /* first we will check if we need to reclaim pagecache memory */
137 if (OomReclaimPageCache() == FALSE) {//
138 LOS_SpinUnlock(&g_oomSpinLock);
139 goto NO_VICTIM_PROCESS;
140 }
141
142 /* get free bytes */
143 OsVmPhysUsedInfoGet(&usedPm, &totalPm);
144 isLowMemory = ((totalPm - usedPm) << PAGE_SHIFT) < g_oomCB->lowMemThreshold;
145 LOS_SpinUnlock(&g_oomSpinLock);
146 if (isLowMemory) {
147 PRINTK("[oom] OS is in low memory state\n"
148 "total physical memory: %#x(byte), used: %#x(byte),"
149 "free: %#x(byte), low memory threshold: %#x(byte)\n",
150 totalPm << PAGE_SHIFT, usedPm << PAGE_SHIFT,
151 (totalPm - usedPm) << PAGE_SHIFT, g_oomCB->lowMemThreshold);
152 }
153
154NO_VICTIM_PROCESS:
155 return isLowMemory;
156}
157
158#ifdef LOSCFG_ENABLE_OOM_LOOP_TASK //内存溢出监测任务开关
159STATIC VOID OomWriteEvent(VOID) // OomTaskInit中创建的定时器回调
160{
161 OsWriteResourceEvent(OS_RESOURCE_EVENT_OOM);//广播内存溢出事件
162}
163#endif
164//打印内存不足时的信息
165LITE_OS_SEC_TEXT_MINOR VOID OomInfodump(VOID) //打印内存溢出信息
166{
167 PRINTK("[oom] oom loop task status: %s\n"
168 " oom low memory threshold: %#x(byte)\n"
169 " oom reclaim memory threshold: %#x(byte)\n"
170 " oom check interval: %d(microsecond)\n",
171 g_oomCB->enabled ? "enabled" : "disabled",
174}
175///设置低内存门槛
176LITE_OS_SEC_TEXT_MINOR VOID OomSetLowMemThreashold(UINT32 lowMemThreshold)
177{
178 if ((lowMemThreshold > OOM_DEFAULT_LOW_MEM_THRESHOLD_MAX)) {
179 PRINTK("[oom] low memory threshold %#x(byte) invalid,"
180 "should be in [%#x, %#x](byte)\n",
181 lowMemThreshold, OOM_DEFAULT_LOW_MEM_THRESHOLD_MIN,
182 OOM_DEFAULT_LOW_MEM_THRESHOLD_MAX);
183 } else {
184 g_oomCB->lowMemThreshold = lowMemThreshold;
185 PRINTK("[oom] set oom low memory threshold %#x(byte) successful\n",
187 }
188}
189///设置回收内存的门槛
190LITE_OS_SEC_TEXT_MINOR VOID OomSetReclaimMemThreashold(UINT32 reclaimMemThreshold)
191{
192 UINT32 totalPm = 0;
193 UINT32 usedPm = 0;
194
195 OsVmPhysUsedInfoGet(&usedPm, &totalPm);
196 if ((reclaimMemThreshold >= (totalPm << PAGE_SHIFT)) ||
197 (reclaimMemThreshold < g_oomCB->lowMemThreshold)) {
198 PRINTK("[oom] reclaim memory threshold %#x(byte) invalid,"
199 "should be in [%#x, %#x)(byte)\n",
200 reclaimMemThreshold, g_oomCB->lowMemThreshold, (totalPm << PAGE_SHIFT));
201 } else {
202 g_oomCB->reclaimMemThreshold = reclaimMemThreshold;
203 PRINTK("[oom] set oom reclaim memory threshold %#x(byte) successful\n",
205 }
206}
207///设置监控间隔
208LITE_OS_SEC_TEXT_MINOR VOID OomSetCheckInterval(UINT32 checkInterval)
209{
210 if ((checkInterval >= OOM_CHECK_MIN) && (checkInterval <= OOM_CHECK_MAX)) {
211 g_oomCB->checkInterval = checkInterval;
212 PRINTK("[oom] set oom check interval (%d)ms successful\n",
214 } else {
215 PRINTK("[oom] set oom check interval (%d)ms failed, should be in [%d, %d]\n",
216 g_oomCB->checkInterval, OOM_CHECK_MIN, OOM_CHECK_MAX);
217 }
218}
219///内存不足监控任务初始化, OOM 通过开一个软件定时器来检查内存的使用情况
220LITE_OS_SEC_TEXT_MINOR UINT32 OomTaskInit(VOID)
221{
223 if (g_oomCB == NULL) {
224 VM_ERR("oom task init failed, malloc OomCB failed.");
225 return LOS_NOK;
226 }
227
228 g_oomCB->lowMemThreshold = OOM_DEFAULT_LOW_MEM_THRESHOLD; //运行任务的门槛
229 g_oomCB->reclaimMemThreshold = OOM_DEFAULT_RECLAIM_MEM_THRESHOLD; //回收内存的门槛
230 g_oomCB->checkInterval = OOM_DEFAULT_CHECK_INTERVAL; //检测时间间隔 1S
231 g_oomCB->processVictimCB = (OomFn)OomKillProcess; //出问题时对进程的处理函数
232 g_oomCB->scoreCB = (OomFn)OomScoreProcess; //统计进程占用的物理内存
233 g_oomCB->enabled = FALSE; //是否启用监控
234
235#ifdef LOSCFG_ENABLE_OOM_LOOP_TASK //内存溢出检测开关
236 g_oomCB->enabled = TRUE;
238 &g_oomCB->swtmrID, (UINTPTR)g_oomCB);//创建检测定时器
239 if (ret != LOS_OK) {
240 return ret;
241 }
242
243 return LOS_SwtmrStart(g_oomCB->swtmrID);//启动定时器
244#else
245 return LOS_OK;
246#endif
247}
248
249LOS_MODULE_INIT(OomTaskInit, LOS_INIT_LEVEL_KMOD_TASK);//初始化内存监控模块
250
251#endif
252
VOID * LOS_MemAlloc(VOID *pool, UINT32 size)
从指定内存池中申请size长度的内存,注意这可不是从内核堆空间中申请内存
Definition: los_memory.c:1123
UINT8 * m_aucSysMem0
异常交互动态内存池地址的起始地址,当不支持异常交互特性时,m_aucSysMem0等于m_aucSysMem1。
Definition: los_memory.c:107
LITE_OS_SEC_TEXT UINT32 LOS_SwtmrStart(UINT16 swtmrID)
接口函数 启动定时器 参数定时任务ID
Definition: los_swtmr.c:764
VOID(* SWTMR_PROC_FUNC)(UINTPTR arg)
Define the type of a callback function that handles software timer timeout.
Definition: los_swtmr.h:260
LITE_OS_SEC_TEXT_INIT UINT32 LOS_SwtmrCreate(UINT32 interval, UINT8 mode, SWTMR_PROC_FUNC handler, UINT16 *swtmrID, UINTPTR arg)
创建定时器,设置定时器的定时时长、定时器模式、回调函数,并返回定时器ID
Definition: los_swtmr.c:712
@ LOS_SWTMR_MODE_PERIOD
Definition: los_swtmr.h:233
UINT32(* OomFn)(UINTPTR param)
Definition: los_oom.h:49
VOID LOS_SpinLock(SPIN_LOCK_S *lock)
Definition: los_spinlock.c:50
VOID LOS_SpinUnlock(SPIN_LOCK_S *lock)
Definition: los_spinlock.c:84
LITE_OS_SEC_TEXT VOID OsWriteResourceEvent(UINT32 events)
Definition: los_task.c:1642
unsigned long UINTPTR
Definition: los_typedef.h:68
unsigned int UINT32
Definition: los_typedef.h:57
size_t BOOL
Definition: los_typedef.h:88
VOID OsVmPhysUsedInfoGet(UINT32 *usedCount, UINT32 *totalCount)
获取物理内存的使用信息,两个参数接走数据
Definition: los_vm_dump.c:558
UINT32 OsUProcessPmUsage(LosVmSpace *space, UINT32 *sharePm, UINT32 *actualPm)
虚拟空间物理内存的使用情况,参数同时带走共享物理内存 sharePm和actualPm 单位是字节
Definition: los_vm_dump.c:199
int OsTryShrinkMemory(size_t nPage)
Definition: los_vm_scan.c:340
STATIC INLINE STATUS_T LOS_MuxAcquire(LosMux *m)
Definition: los_vm_lock.h:48
STATIC INLINE STATUS_T LOS_MuxRelease(LosMux *m)
Definition: los_vm_lock.h:53
LITE_OS_SEC_TEXT_MINOR UINT32 OomTaskInit(VOID)
内存不足监控任务初始化, OOM 通过开一个软件定时器来检查内存的使用情况
Definition: oom.c:220
LITE_OS_SEC_TEXT_MINOR VOID OomSetCheckInterval(UINT32 checkInterval)
设置监控间隔
Definition: oom.c:208
LITE_OS_SEC_TEXT_MINOR STATIC UINT32 OomScoreProcess(LosProcessCB *candidateProcess)
Definition: oom.c:53
LITE_OS_SEC_BSS OomCB * g_oomCB
Definition: oom.c:50
LITE_OS_SEC_TEXT_MINOR VOID OomSetReclaimMemThreashold(UINT32 reclaimMemThreshold)
设置回收内存的门槛
Definition: oom.c:190
LITE_OS_SEC_TEXT_MINOR STATIC BOOL OomReclaimPageCache(VOID)
内存不足时回收页高速缓存
Definition: oom.c:91
LOS_MODULE_INIT(OomTaskInit, LOS_INIT_LEVEL_KMOD_TASK)
LITE_OS_SEC_TEXT_MINOR VOID OomSetLowMemThreashold(UINT32 lowMemThreshold)
设置低内存门槛
Definition: oom.c:176
STATIC VOID OomWriteEvent(VOID)
Definition: oom.c:159
LITE_OS_SEC_TEXT_MINOR STATIC UINT32 OomKillProcess(UINTPTR param)
用于设置 g_oomCB->processVictimCB 回调函数
Definition: oom.c:68
LITE_OS_SEC_TEXT_MINOR STATIC UINT32 OomForceShrinkMemory(VOID)
强制收缩内存
Definition: oom.c:74
LITE_OS_SEC_TEXT_MINOR BOOL OomCheckProcess(VOID)
Definition: oom.c:124
LITE_OS_SEC_TEXT_MINOR VOID OomInfodump(VOID)
Definition: oom.c:165
static SPIN_LOCK_INIT(g_oomSpinLock)
Definition: los_oom.h:51
BOOL enabled
Definition: los_oom.h:58
UINT32 checkInterval
Definition: los_oom.h:54
UINT32 lowMemThreshold
Definition: los_oom.h:52
OomFn processVictimCB
Definition: los_oom.h:55
OomFn scoreCB
Definition: los_oom.h:56
UINT16 swtmrID
Definition: los_oom.h:57
UINT32 reclaimMemThreshold
Definition: los_oom.h:53
LosVmSpace * vmSpace
LosMux regionMux
Definition: los_vm_map.h:149