保留内存lowmem_rerve浅析

更新时间:2023-06-29 09:08:58 阅读: 评论:0

保留内存lowmem_rerve浅析
⼀、保留内存的⽤武之地
要了解内存区的保留内存,我们⾸先要知道这个保留内存⽤在何处。实际上它在内核⽔线计算时会⽤到,那内核是如何计算⽔线的呢?保留内存到底在⽔线计算起到什么作⽤呢?我们先来跟踪代码⼀探究竟。
为了⽅便说明,这⾥只针对UMA架构。UMA架构物理内存的分配最终由__alloc_pages_nodemask()函数实现。
structpage* __alloc_pages_nodemask(gfp_tgfp_mask,unsignedintorder,
structzonelist*zonelist,nodemask_t*nodemask)
{
structzoneref*preferred_zoneref;
......
structalloc_contextac= {
/* ac.high_zoneidx的值与⼊参gfp_mask有关系,即主要查看gftp_mask是否有特别指定__GFP_DMA|DMA32|HIGH|MOVEABLE*/
.high_zoneidx = gfp_zone(gfp_mask),/* 如果gfp_mask & __GFP_DMA , high_zoneidx == ZONE_DMA ,英语音标表
gfp_mask & __GFP_DMA32 , high_zoneidx == ZONE_DMA32,
if ((flags & (__GFP_HIGHMEM | __GFP_MOVABLE)) == (__GFP_HIGHMEM | __GFP_MOVABLE)) high_zoneidx == ZONE_MOVABLE
if (flags & __GFP_HIGHMEM) return ZONE_HIGHMEM;
return ZONE_NORMAL */
.nodemask = nodemask,
.migratetype = gfpflags_to_migratetype(gfp_mask),
绯闻女孩第一季高清下载
};
......
/* Dirty zone balancing only done in the fast path */3d效果图培训
ac.spread_dirty_pages = (gfp_mask & __GFP_WRITE);
......
/* 从HIGH往DMA⽅向选择第⼀个满⾜(不⼤于)ac.high_zoneidx的zoneref */
preferred_zoneref = first_zones_list, ac.high_zoneidx,
&ac.preferred_zone);
......
最新大学排行榜
ac.classzone_idx = zonelist_zone_idx(preferred_zoneref);/* zoneref->zone_idx */
......
/* ac.classzone_idx 和 ac.zonelist 可以基本确定我们优先从哪个zone分配内存 */
page = __alloc_pages_slowpath(alloc_mask, order, &ac);
}
__alloc_pages_slowpath()-->get_page_from_freelist() 这个函数中最终会进⾏⽔线检查。
zone_watermark_ok()--> __zone_watermark_ok(struct zone *z, unsigned int order,unsigned long mark, int classzone_idx, int alloc_flags,long free_pages)
veral是什么意思
这个是⽔线检查的主要实现函数,在检查前会对内存区的空闲内存free_pages和⽔线mark根据内存分配标志进⾏调整。
高考英语改革
[1] 根据alloc_flags调整⽔线和free_pages;
free_pages -= (1<< order) -1
/* 降低⽔线,使其可更容易分配到内存 */
if(alloc_flags & ALLOC_HIGH)
min -= min /2;
raytrace
/* 若未设置ALLOC_HARDER,则需要保留z->nr_rerved_highatomic内存以不时之需 */
if(likely(!alloc_harder))
free_pages -= z->nr_rerved_highatomic;
el
min -= min /4;/* 否则的话降低⽔线使其更容器分配到内存 */
#ifdefCONFIG_CMA
/* 如果配置了CMA,则没有明确指明从CMA分配时(即没有设置ALLOC_CMA)需要保留出CMA内存 */
/* If allocation can't u CMA areas don't u free CMA pages */
if(!(alloc_flags & ALLOC_CMA))
diaper ointment
free_pages -= zone_page_state(z, NR_FREE_CMA_PAGES);
#endif
[2] 调整好⽔线后开始计算是否到达⽔线
if(free_pages <= min + z->lowmem_rerve[classzone_idx])
returnfal;
在这⾥内存区的保留内存终于浮出⽔⾯。这⾥的⽔线实际等于 min + z->lowmem_rerve[classzone_idx]。min我们实际上了解了就是zone-
自考英语二
>watermark[NR_WMARK]中的⼀个值,它的取值跟实际情况关;⽽z->lowmem_rerve[classzone_idx]就是我们寻找已久的保留内存。
也就是说内核在进⾏⽔线检查时,不仅仅要检查内存区的真正的⽔线"zone->watermark[x]",还要考虑保留内存。
建设工程施工
有时候我们会在某个zone还有⽐较客观的内存数量时(远超min⽔线)时,仍然会发⽣内存分配失败,这时可以考虑⼀下是否是保留区内存太⼤导致。
⼆、认识保留内存
2.1 基本概念
好了,是时候了解⼀下什么是lowmem_rerve了。
kernel在分配内存时,可能会涉及到多个zone,分配会尝试从zonelist第⼀个zone分配,如果失败就会尝试下⼀个低级的zone(这⾥的低级仅仅指zone内存的位置,实际上低地址zone是更稀缺的资源)。考虑这样⼀种场景应⽤进程通过内存映射申请Highmem 并且加mlock分配,如果此时HIGH zone⽆法满⾜分配,则会尝试从Normal进⾏分配。问题来了,应⽤进程在从HIHG“降”到Normal区的分配请求有可能会耗尽Normal 区的内存,⽽且由于mlock⼜⽆法回收,最终的结果就是Normal区⽆内存--在i386这样的架构上内核能够正常访问的线性区正是Normal区,这就导致kernel可能⽆法正常⼯作,然⽽HIGH zone却可能有⾜量的可回收内存。
针对这个情形,当Normal zone在碰到来⾃HIGH的分配请求时,可以通过lowmem_rerve声明:可以使⽤我的内存,但是必须要保留lowmem_rerve[NORMAL]给我⾃⼰使⽤。
同样当从Normal失败后,会尝试从zonelist中的DMA申请分配,通过lowmem_rerve[DMA],限制来⾃HIGHMEM和Normal的分配请求。
2.2 保留内存的初始化
有了上⾯的铺垫我们看⼀下各个区的lowmem_reve[]是如何配置的,各个区究竟保留了多少内存。
1】内核定义了⼀个long lowmem_rerve[MAX_NR_ZONES]数组来表⽰各个区的保留内存。这个数组的⼤⼩MAX_NR_ZONES与内核配置有关系,例如内核使能了CONFIG_ZONE_DMA、CONFIG_ZONE_DMA32、则MAX_NR_ZONES值为4,他们是:
enumzone_type {
ZONE_DMA,/* 0 */
ZONE_DMA32,
ZONE_NORMAL,
ZONE_MOVABLE,
__MAX_NR_ZONES/* 3 */
};
【2】那各个lowmem_rerve[MAX_NR_ZONES]是如何计算的呢?
我们来看看这个数组的初始化流程,它是由tup_per_zone_lowmem_rerve(void)函数来完成的。
四、总结
这篇⽂章还是从实际遇到的问题引出的。之前在某个环境出现过Normal区内存量远⾼于⽔线时出现OOM的情况,最后查明原因就是因为保留内存太多导致。最终通过调整sysctl_lowmem_rerve_ratio参数进⾏规避。

本文发布于:2023-06-29 09:08:58,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/90/161411.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:内存   保留   分配   内核   计算
相关文章
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图