提交 8f5e0266 编写于 作者: 鸿蒙内核源码分析's avatar 鸿蒙内核源码分析

2020年最后一次代码提交,预祝2021年注释中文版牛气冲天, 本次完成当内存不足时的处理注解.

搜索 @note_pic 方便理解画的字符图
搜索 @note_why 尚未看明白的地方,如果您看明白了,请告知完善
搜索 @note_thinking 一点思考和吐槽的地方
搜索 @note_#if0 由第三方项目提供不由内核源码中定义的极为重要的结构体,为方便理解而添加的
搜索 @note_good 给源码点赞
上级 a7c24a4b
......@@ -40,20 +40,20 @@
#define OOM_DEFAULT_CHECK_INTERVAL 100 /* 1s */
#define OOM_CHECK_MAX 1000 /* 10s */
#define OOM_DEFAULT_LOW_MEM_THRESHOLD 0x80000 /* 512KByte */
#define OOM_DEFAULT_LOW_MEM_THRESHOLD_MIN 0 /* 0, means always no memory */
#define OOM_DEFAULT_LOW_MEM_THRESHOLD_MAX 0x100000 /* 1MByte */
#define OOM_DEFAULT_LOW_MEM_THRESHOLD 0x80000 /* 512KByte */ //低内存门槛
#define OOM_DEFAULT_LOW_MEM_THRESHOLD_MIN 0 /* 0, means always no memory */
#define OOM_DEFAULT_LOW_MEM_THRESHOLD_MAX 0x100000 /* 1MByte */
#define OOM_DEFAULT_RECLAIM_MEM_THRESHOLD 0x500000 /* 5MByte */
#define OOM_DEFAULT_RECLAIM_MEM_THRESHOLD 0x500000 /* 5MByte */ //默认回收内存门槛
typedef UINT32 (*OomFn)(UINTPTR param);//内存溢出的回调函数定义
typedef struct { //内存溢出控制块(描述符)
UINT32 lowMemThreshold; /* byte */ //最低运行内存
UINT32 reclaimMemThreshold; /* byte */ //回收内存起点
UINT32 checkInterval; /* microsecond */
OomFn processVictimCB; /* process victim process cb function */
OomFn scoreCB; /* out of memory, the process score function */ //内存不足时,进程得分函数
UINT32 checkInterval; /* microsecond */ //检测间隔,毫秒级
OomFn processVictimCB; /* process victim process cb function */ //出问题时对进程的处理函数
OomFn scoreCB; /* out of memory, the process score function */ //内存不足时,统计进程占用的物理内存
UINT16 swtmrID; //定时器ID
BOOL enabled; /* oom is enabled or not *///是否启用了内存溢出监控
} OomCB;
......
......@@ -118,8 +118,8 @@ enum OsPageFlags {
#define PGOFF_MAX 2000
#define MAX_SHRINK_PAGECACHE_TRY 2
#define VM_FILEMAP_MAX_SCAN (SYS_MEM_SIZE_DEFAULT >> PAGE_SHIFT)
#define VM_FILEMAP_MIN_SCAN 32
#define VM_FILEMAP_MAX_SCAN (SYS_MEM_SIZE_DEFAULT >> PAGE_SHIFT) //扫描文件映射页最大数量
#define VM_FILEMAP_MIN_SCAN 32 //扫描文件映射页最小数量
//给页面贴上被锁的标签
STATIC INLINE VOID OsSetPageLocked(LosVmPage *page)
{
......
......@@ -432,7 +432,7 @@ STATIC INT32 OsFlushDirtyPage(LosFilePage *fpage)
return ret;
}
//把一页脏数据拷贝给新页,老脏页撕掉脏页标签
//备份脏页,老脏页撕掉脏页标签
LosFilePage *OsDumpDirtyPage(LosFilePage *oldFPage)
{
LosFilePage *newFPage = NULL;
......@@ -453,7 +453,7 @@ LosFilePage *OsDumpDirtyPage(LosFilePage *oldFPage)
return newFPage;
}
//处理脏页数据
//冲洗脏页数据,将脏页数据回写磁盘
VOID OsDoFlushDirtyPage(LosFilePage *fpage)
{
if (fpage == NULL) {
......
......@@ -141,7 +141,7 @@ ref:0, act:0 --> ref:1, act:0
ref:1, act:0 --> ref:0, act:1
ref:0, act:1 --> ref:1, act:1
*/
VOID OsPageRefIncLocked(LosFilePage *fpage)
VOID OsPageRefIncLocked(LosFilePage *fpage)// ref ,act 标签转换功能
{
BOOL isOrgActive;
UINT32 intSave;
......@@ -151,16 +151,16 @@ VOID OsPageRefIncLocked(LosFilePage *fpage)
return;
}
LOS_SpinLockSave(&fpage->physSeg->lruLock, &intSave);
LOS_SpinLockSave(&fpage->physSeg->lruLock, &intSave);//要处理lruList,先拿锁
page = fpage->vmPage;
isOrgActive = OsIsPageActive(page);
page = fpage->vmPage;//拿到物理页框
isOrgActive = OsIsPageActive(page);//页面是否在活动
if (OsIsPageReferenced(page) && !OsIsPageActive(page)) {
OsCleanPageReferenced(page);
OsSetPageActive(page);
if (OsIsPageReferenced(page) && !OsIsPageActive(page)) {//身兼 不活动和引用标签
OsCleanPageReferenced(page);//撕掉引用标签 ref:1, act:0 --> ref:0, act:1
OsSetPageActive(page); //贴上活动标签
} else if (!OsIsPageReferenced(page)) {
OsSetPageReferenced(page);
OsSetPageReferenced(page);//ref:0, act:0 --> ref:1, act:0
}
if (!isOrgActive && OsIsPageActive(page)) {
......@@ -185,7 +185,7 @@ ref:1, act:1 --> ref:0, act:1
ref:0, act:1 --> ref:1, act:0
ref:1, act:0 --> ref:0, act:0
*/
VOID OsPageRefDecNoLock(LosFilePage *fpage)
VOID OsPageRefDecNoLock(LosFilePage *fpage) // ref ,act 标签转换功能
{
BOOL isOrgActive;
LosVmPage *page = NULL;
......@@ -215,25 +215,25 @@ VOID OsShrinkActiveList(LosVmPhysSeg *physSeg, int nScan)
LosFilePage *fnext = NULL;
LOS_DL_LIST *activeFile = &physSeg->lruList[VM_LRU_ACTIVE_FILE];
LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(fpage, fnext, activeFile, LosFilePage, lru) {
if (LOS_SpinTrylock(&fpage->mapping->list_lock) != LOS_OK) {
continue;
LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(fpage, fnext, activeFile, LosFilePage, lru) {//一页一页处理
if (LOS_SpinTrylock(&fpage->mapping->list_lock) != LOS_OK) {//尝试获取文件页所在的page_mapping锁
continue;//接着处理下一文件页
}
/* happend when caller hold cache lock and try reclaim this page */
if (OsIsPageLocked(fpage->vmPage)) {
LOS_SpinUnlock(&fpage->mapping->list_lock);
continue;
/* happend when caller hold cache lock and try reclaim this page *///调用方持有缓存锁并尝试回收此页时发生
if (OsIsPageLocked(fpage->vmPage)) {//页面是否被锁
LOS_SpinUnlock(&fpage->mapping->list_lock);//失败时,一定要释放page_mapping锁.
continue;//接着处理下一文件页
}
if (OsIsPageMapped(fpage) && (fpage->flags & VM_MAP_REGION_FLAG_PERM_EXECUTE)) {
LOS_SpinUnlock(&fpage->mapping->list_lock);
continue;
if (OsIsPageMapped(fpage) && (fpage->flags & VM_MAP_REGION_FLAG_PERM_EXECUTE)) {//文件页是否被映射而且是个可执行文件 ?
LOS_SpinUnlock(&fpage->mapping->list_lock);//是时,一定要释放page_mapping锁.
continue;//接着处理下一文件页
}
//找了可以收缩的文件页
OsPageRefDecNoLock(fpage); //将页面移到未活动文件链表
OsPageRefDecNoLock(fpage);
LOS_SpinUnlock(&fpage->mapping->list_lock);
LOS_SpinUnlock(&fpage->mapping->list_lock); //释放page_mapping锁.
if (--nScan <= 0) {
break;
......@@ -251,36 +251,36 @@ int OsShrinkInactiveList(LosVmPhysSeg *physSeg, int nScan, LOS_DL_LIST *list)
LosFilePage *ftemp = NULL;
LOS_DL_LIST *inactive_file = &physSeg->lruList[VM_LRU_INACTIVE_FILE];
LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(fpage, fnext, inactive_file, LosFilePage, lru) {
LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(fpage, fnext, inactive_file, LosFilePage, lru) {//遍历链表一页一页处理
flock = &fpage->mapping->list_lock;
if (LOS_SpinTrylock(flock) != LOS_OK) {
continue;
if (LOS_SpinTrylock(flock) != LOS_OK) {//尝试获取文件页所在的page_mapping锁
continue;//接着处理下一文件页
}
page = fpage->vmPage;
if (OsIsPageLocked(page)) {
page = fpage->vmPage;//获取物理页框
if (OsIsPageLocked(page)) {//页面是否被锁
LOS_SpinUnlock(flock);
continue;
continue;//接着处理下一文件页
}
if (OsIsPageMapped(fpage) && (OsIsPageDirty(page) || (fpage->flags & VM_MAP_REGION_FLAG_PERM_EXECUTE))) {
LOS_SpinUnlock(flock);
continue;
LOS_SpinUnlock(flock);//文件页是否被映射而且是个脏页获取是个可执行文件 ?
continue;//接着处理下一文件页
}
if (OsIsPageDirty(page)) {//是脏页
ftemp = OsDumpDirtyPage(fpage);
if (ftemp != NULL) {
LOS_ListTailInsert(list, &ftemp->node);
ftemp = OsDumpDirtyPage(fpage);//备份脏页
if (ftemp != NULL) {//备份成功了
LOS_ListTailInsert(list, &ftemp->node);//将脏页挂到参数链表上带走
}
}
OsDeletePageCacheLru(fpage);
OsDeletePageCacheLru(fpage);//将文件页从LRU和pagecache上摘除
LOS_SpinUnlock(flock);
nrReclaimed++;
nrReclaimed++;//成功回收了一页
if (--nScan <= 0) {
if (--nScan <= 0) {//继续回收
break;
}
}
......@@ -294,48 +294,48 @@ bool InactiveListIsLow(LosVmPhysSeg *physSeg)
}
#ifdef LOSCFG_FS_VFS
int OsTryShrinkMemory(size_t nPage)
int OsTryShrinkMemory(size_t nPage)//尝试收缩文件页
{
UINT32 intSave;
size_t totalPages;
size_t nReclaimed = 0;
LosVmPhysSeg *physSeg = NULL;
UINT32 index;
LOS_DL_LIST_HEAD(dirtyList);
LOS_DL_LIST_HEAD(dirtyList);//初始化脏页链表,上面将挂所有脏页用于同步到磁盘后回收
LosFilePage *fpage = NULL;
LosFilePage *fnext = NULL;
if (nPage <= 0) {
nPage = VM_FILEMAP_MIN_SCAN;
nPage = VM_FILEMAP_MIN_SCAN;//
}
if (nPage > VM_FILEMAP_MAX_SCAN) {
nPage = VM_FILEMAP_MAX_SCAN;
}
for (index = 0; index < g_vmPhysSegNum; index++) {
physSeg = &g_vmPhysSeg[index];
for (index = 0; index < g_vmPhysSegNum; index++) {//遍历整个物理段组
physSeg = &g_vmPhysSeg[index];//一段段来
LOS_SpinLockSave(&physSeg->lruLock, &intSave);
totalPages = physSeg->lruSize[VM_LRU_ACTIVE_FILE] + physSeg->lruSize[VM_LRU_INACTIVE_FILE];
if (totalPages < VM_FILEMAP_MIN_SCAN) {
totalPages = physSeg->lruSize[VM_LRU_ACTIVE_FILE] + physSeg->lruSize[VM_LRU_INACTIVE_FILE];//统计所有文件页
if (totalPages < VM_FILEMAP_MIN_SCAN) {//文件页占用内存不多的情况下,怎么处理?
LOS_SpinUnlockRestore(&physSeg->lruLock, intSave);
continue;
continue;//放过这一段,找下一段
}
if (InactiveListIsLow(physSeg)) {
OsShrinkActiveList(physSeg, (nPage < VM_FILEMAP_MIN_SCAN) ? VM_FILEMAP_MIN_SCAN : nPage);
if (InactiveListIsLow(physSeg)) {//未活动页少于活动页的情况
OsShrinkActiveList(physSeg, (nPage < VM_FILEMAP_MIN_SCAN) ? VM_FILEMAP_MIN_SCAN : nPage);//缩小活动页
}
nReclaimed += OsShrinkInactiveList(physSeg, nPage, &dirtyList);
nReclaimed += OsShrinkInactiveList(physSeg, nPage, &dirtyList);//缩小未活动页,带出脏页链表
LOS_SpinUnlockRestore(&physSeg->lruLock, intSave);
if (nReclaimed >= nPage) {
break;
if (nReclaimed >= nPage) {//够了,够了,达到目的了.
break;//退出收缩
}
}
LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(fpage, fnext, &dirtyList, LosFilePage, node) {
OsDoFlushDirtyPage(fpage);
LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(fpage, fnext, &dirtyList, LosFilePage, node) {//遍历处理脏页数据
OsDoFlushDirtyPage(fpage);//冲洗脏页数据,将脏页数据回写磁盘
}
return nReclaimed;
......
......@@ -67,13 +67,13 @@ LITE_OS_SEC_TEXT_MINOR STATIC UINT32 OomScoreProcess(LosProcessCB *candidateProc
#endif
return actualPm;
}
//内存不足时,进程
//用于设置 g_oomCB->processVictimCB 回调函数
LITE_OS_SEC_TEXT_MINOR STATIC UINT32 OomKillProcess(UINTPTR param)
{
/* we will not kill process, and do nothing here */
return LOS_OK;
}
//强制收缩内存
LITE_OS_SEC_TEXT_MINOR STATIC UINT32 OomForceShrinkMemory(VOID)
{
UINT32 i;
......@@ -83,13 +83,14 @@ LITE_OS_SEC_TEXT_MINOR STATIC UINT32 OomForceShrinkMemory(VOID)
* TryShrinkMemory maybe reclaim 0 pages in the first time from active list
* to inactive list, and in the second time reclaim memory from inactive list.
*/
//TryShrinkMemory可能会在第一时间从活动列表中回收0页到非活动列表,并在第二次从非活动列表中回收内存。
for (i = 0; i < MAX_SHRINK_PAGECACHE_TRY; i++) {
reclaimMemPages += OsTryShrinkMemory(0);
}
return reclaimMemPages;
}
//内存不足时回收页高速缓存
LITE_OS_SEC_TEXT_MINOR STATIC BOOL OomReclaimPageCache(VOID)
{
UINT32 totalPm = 0;
......@@ -99,30 +100,31 @@ LITE_OS_SEC_TEXT_MINOR STATIC BOOL OomReclaimPageCache(VOID)
UINT32 i;
for (i = 0; i < MAX_SHRINK_PAGECACHE_TRY; i++) {
OsVmPhysUsedInfoGet(&usedPm, &totalPm);
isReclaimMemory = ((totalPm - usedPm) << PAGE_SHIFT) < g_oomCB->reclaimMemThreshold;
if (isReclaimMemory) {
OsVmPhysUsedInfoGet(&usedPm, &totalPm);//获取总的和已经使用的物理内存数量
isReclaimMemory = ((totalPm - usedPm) << PAGE_SHIFT) < g_oomCB->reclaimMemThreshold;//检查是否过了回收门槛
if (isReclaimMemory) {//要回收了
/*
* we do force memory reclaim from page cache here.
* if we get memory, we will reclaim pagecache memory again.
* if there is no memory to reclaim, we will return.
*/
reclaimMemPages = OomForceShrinkMemory();
if (reclaimMemPages > 0) {
//在这里强制从页缓存中回收内存,
reclaimMemPages = OomForceShrinkMemory();//强制回收内存
if (reclaimMemPages > 0) {//如果得到内存,将再次回收pagecache内存
continue;
}
}
break;
break;//实在没有内存可回收
}
return isReclaimMemory;
return isReclaimMemory;//返回回收的数量
}
/*
* check is low memory or not, if low memory, try to kill process. //检查内存是否不足,如果内存不足,请尝试终止进程。
* return is kill process or not. //返回是否kill进程
* check is low memory or not, if low memory, try to kill process.
* return is kill process or not.
*/
LITE_OS_SEC_TEXT_MINOR BOOL OomCheckProcess(VOID)
LITE_OS_SEC_TEXT_MINOR BOOL OomCheckProcess(VOID)//检查内存是否不足,如果内存不足,请尝试终止进程,返回是否kill进程
{
UINT32 totalPm;
UINT32 usedPm;
......@@ -135,7 +137,7 @@ LITE_OS_SEC_TEXT_MINOR BOOL OomCheckProcess(VOID)
LOS_SpinLock(&g_oomSpinLock);
/* first we will check if we need to reclaim pagecache memory */
if (OomReclaimPageCache() == FALSE) {
if (OomReclaimPageCache() == FALSE) {//
goto NO_VICTIM_PROCESS;
}
......@@ -158,10 +160,10 @@ NO_VICTIM_PROCESS:
#ifdef LOSCFG_ENABLE_OOM_LOOP_TASK //内存溢出监测任务开关
STATIC VOID OomWriteEvent(VOID) // OomTaskInit中创建的定时器回调
{
OsWriteResourceEvent(OS_RESOURCE_EVENT_OOM);//内存溢出事件
OsWriteResourceEvent(OS_RESOURCE_EVENT_OOM);//广播内存溢出事件
}
#endif
//打印内存不足时的信息
LITE_OS_SEC_TEXT_MINOR VOID OomInfodump(VOID) //打印内存溢出信息
{
PRINTK("[oom] oom loop task status: %s\n"
......@@ -172,7 +174,7 @@ LITE_OS_SEC_TEXT_MINOR VOID OomInfodump(VOID) //打印内存溢出信息
g_oomCB->lowMemThreshold, g_oomCB->reclaimMemThreshold,
g_oomCB->checkInterval);
}
//设置低内存门槛
LITE_OS_SEC_TEXT_MINOR VOID OomSetLowMemThreashold(UINT32 lowMemThreshold)
{
if ((lowMemThreshold > OOM_DEFAULT_LOW_MEM_THRESHOLD_MAX)) {
......@@ -186,7 +188,7 @@ LITE_OS_SEC_TEXT_MINOR VOID OomSetLowMemThreashold(UINT32 lowMemThreshold)
g_oomCB->lowMemThreshold);
}
}
//设置回收内存的门槛
LITE_OS_SEC_TEXT_MINOR VOID OomSetReclaimMemThreashold(UINT32 reclaimMemThreshold)
{
UINT32 totalPm = 0;
......@@ -204,7 +206,7 @@ LITE_OS_SEC_TEXT_MINOR VOID OomSetReclaimMemThreashold(UINT32 reclaimMemThreshol
g_oomCB->reclaimMemThreshold);
}
}
//设置监控间隔
LITE_OS_SEC_TEXT_MINOR VOID OomSetCheckInterval(UINT32 checkInterval)
{
if ((checkInterval >= OOM_CHECK_MIN) && (checkInterval <= OOM_CHECK_MAX)) {
......@@ -216,7 +218,7 @@ LITE_OS_SEC_TEXT_MINOR VOID OomSetCheckInterval(UINT32 checkInterval)
g_oomCB->checkInterval, OOM_CHECK_MIN, OOM_CHECK_MAX);
}
}
//内存溢出任务初始化
//内存不足监控任务初始化, OOM 通过开一个软件定时器来检查内存的使用情况
LITE_OS_SEC_TEXT_MINOR UINT32 OomTaskInit(VOID)
{
g_oomCB = (OomCB *)LOS_MemAlloc(m_aucSysMem0, sizeof(OomCB));
......@@ -225,12 +227,12 @@ LITE_OS_SEC_TEXT_MINOR UINT32 OomTaskInit(VOID)
return LOS_NOK;
}
g_oomCB->lowMemThreshold = OOM_DEFAULT_LOW_MEM_THRESHOLD;
g_oomCB->reclaimMemThreshold = OOM_DEFAULT_RECLAIM_MEM_THRESHOLD;
g_oomCB->checkInterval = OOM_DEFAULT_CHECK_INTERVAL;
g_oomCB->processVictimCB = (OomFn)OomKillProcess;
g_oomCB->scoreCB = (OomFn)OomScoreProcess;
g_oomCB->enabled = FALSE;
g_oomCB->lowMemThreshold = OOM_DEFAULT_LOW_MEM_THRESHOLD; //运行任务的门槛
g_oomCB->reclaimMemThreshold = OOM_DEFAULT_RECLAIM_MEM_THRESHOLD; //回收内存的门槛
g_oomCB->checkInterval = OOM_DEFAULT_CHECK_INTERVAL; //检测时间间隔 1S
g_oomCB->processVictimCB = (OomFn)OomKillProcess; //出问题时对进程的处理函数
g_oomCB->scoreCB = (OomFn)OomScoreProcess; //统计进程占用的物理内存
g_oomCB->enabled = FALSE; //是否启用监控
#ifdef LOSCFG_ENABLE_OOM_LOOP_TASK //内存溢出检测开关
g_oomCB->enabled = TRUE;
......@@ -240,7 +242,7 @@ LITE_OS_SEC_TEXT_MINOR UINT32 OomTaskInit(VOID)
return ret;
}
return LOS_SwtmrStart(g_oomCB->swtmrID);
return LOS_SwtmrStart(g_oomCB->swtmrID);//启动定时器
#else
return LOS_OK;
#endif
......
git add -A
git commit -m '开始注解(OOM)内存不足时的处理.
git commit -m '2020年最后一次代码提交,预祝2021年注释中文版牛气冲天, 本次完成当内存不足时的处理注解.
搜索 @note_pic 方便理解画的字符图
搜索 @note_why 尚未看明白的地方,如果您看明白了,请告知完善
搜索 @note_thinking 一点思考和吐槽的地方
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册