免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 3978 | 回复: 14
打印 上一主题 下一主题

[内存管理] system oom 分析 [复制链接]

论坛徽章:
1
拜羊年徽章
日期:2015-03-03 16:15:43
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2015-03-07 12:11 |只看该作者 |倒序浏览
系统运行一周后,发生oom
oom发生的时候,有70M的RAM用于page cache, kernel不能释放
在嵌入式系统里,没有disk, swap disabled. 按道理不应该有这么多page cache不能释放
在没有swap的系统,哪些东东会占用这样多的page cache而释放不了?
socket?  mmap-file?

论坛徽章:
2
寅虎
日期:2014-11-25 21:47:342015小元宵徽章
日期:2015-03-06 15:58:18
2 [报告]
发表于 2015-03-07 17:48 |只看该作者
即使page cache比较大,如果系统内存吃紧,内存会shrink后,努力去满足用户态的程序。
该问题是否必现,如果能复现,最好抓取oom前的cat /proc/meminfo 和top(按照内存使用量排序)的信息。

论坛徽章:
1
拜羊年徽章
日期:2015-03-03 16:15:43
3 [报告]
发表于 2015-03-09 05:46 |只看该作者
本帖最后由 linuxfellow 于 2015-03-09 07:34 编辑

回复 2# 镇水铁牛
通过分析,可能系统保留的内存过少。
system ram:   128M
default min_free_kybyes =1442
The RAM reserved is 1.4M bytes.

Only ZONE_NORMAL is available in the system, no swap.  Basing on the min_free_kybyes configuration, 水印通过如下计算得到:

watermark[min] = 1442k >> 12 =360 页
watermark[low] = 1.25*watermark[min] = 450
watermark[low] = 1.5*watermark[min] = 540

When the system free pages is close to watermark[min], OOM is triggered.
可能的情况:
watermark[low]与watermark[min]差别太小,  90页=360kbytes
系统仍然有451页空闲页面,下一次内存申请大小大于360kbytes,kswapd来不及启动,直接进入direct memory reclaim
当系统运行接近到360页空闲页面时, 如果下次页面申请是__GFP_ATOMIC,  这种情况下,direct memory reclaim也是不允许的. direct memory reclaim要调用try_to_free_pages(),而这是一个阻塞过程,不能用于__GFP_ATOMIC.  这时候只能从预留的min_free_kybyes 获取页面;当min_free_kybyes 消耗殆尽时,OOM killer就被触发

不知是否还有其他状况引起oom,  希望能有更多的建议! 谢谢




   

论坛徽章:
2
寅虎
日期:2014-11-25 21:47:342015小元宵徽章
日期:2015-03-06 15:58:18
4 [报告]
发表于 2015-03-09 22:23 |只看该作者
oom是内存达到极限导致的,要么优化自己的数据结构,降低内存消耗;要么增加内存。

oom发生的时候,有70M的RAM用于page cache, kernel不能释放?增加刷dirty page的时机,实在不行,就考虑direct IO模式访问磁盘。

论坛徽章:
15
射手座
日期:2014-02-26 13:45:082015年迎新春徽章
日期:2015-03-04 09:54:452015年辞旧岁徽章
日期:2015-03-03 16:54:15羊年新春福章
日期:2015-02-26 08:47:552015年亚洲杯之卡塔尔
日期:2015-02-03 08:33:45射手座
日期:2014-12-31 08:36:51水瓶座
日期:2014-06-04 08:33:52天蝎座
日期:2014-05-14 14:30:41天秤座
日期:2014-04-21 08:37:08处女座
日期:2014-04-18 16:57:05戌狗
日期:2014-04-04 12:21:33技术图书徽章
日期:2014-03-25 09:00:29
5 [报告]
发表于 2015-03-10 08:16 |只看该作者
问题主要是__GFP_ATOMIC分配方式,不加这个标记就没问题了。。。

论坛徽章:
1
拜羊年徽章
日期:2015-03-03 16:15:43
6 [报告]
发表于 2015-03-11 12:23 |只看该作者
本帖最后由 linuxfellow 于 2015-03-11 12:55 编辑

netif_receive_skb会申请skb,(alloc_pages(__GPF_ATOMIC), 如果网络接收数据很快,不能及时处理时,会不会产生的skb吃掉大部分内存?

论坛徽章:
1
拜羊年徽章
日期:2015-03-03 16:15:43
7 [报告]
发表于 2015-03-13 02:48 |只看该作者
本帖最后由 linuxfellow 于 2015-03-13 12:14 编辑

Out of memory (oom_kill_allocating_task): Kill process 1699 (Prod) score 0 or sacrifice child
Killed process 1699 (Prod) total-vm:138256kB, anon-rss:1376kB, file-rss:1296kB
progpr invoked oom-killer: gfp_mask=0x201da, order=0, oom_adj=0, oom_score_adj=0
[<c001346c>] (unwind_backtrace+0x0/0xec) from [<c005c520>] (dump_header.isra.17+0x70/0x190)
[<c005c520>] (dump_header.isra.17+0x70/0x190) from [<c005c7c4>] (oom_kill_process.constprop.22+0x68/0x284)
[<c005c7c4>] (oom_kill_process.constprop.22+0x68/0x284) from [<c005cd68>] (out_of_memory+0x1c8/0x360)
[<c005cd68>] (out_of_memory+0x1c8/0x360) from [<c005fed8>] (__alloc_pages_nodemask+0x5e8/0x61
[<c005fed8>] (__alloc_pages_nodemask+0x5e8/0x61 from [<c005b850>] (filemap_fault+0x258/0x4b4)
[<c005b850>] (filemap_fault+0x258/0x4b4) from [<c0070a7c>] (__do_fault+0x68/0x49
[<c0070a7c>] (__do_fault+0x68/0x49 from [<c0073620>] (handle_pte_fault+0x74/0x73c)
[<c0073620>] (handle_pte_fault+0x74/0x73c) from [<c0073d98>] (handle_mm_fault+0xb0/0xf4)
[<c0073d98>] (handle_mm_fault+0xb0/0xf4) from [<c001464c>] (do_page_fault+0x150/0x1f
[<c001464c>] (do_page_fault+0x150/0x1f from [<c0008438>] (do_PrefetchAbort+0x34/0x9
[<c0008438>] (do_PrefetchAbort+0x34/0x9 from [<c000dd74>] (ret_from_exception+0x0/0x10)
Exception stack(0xc6083fb0 to 0xc6083ff
3fa0:                                     00000000 00000002 00000000 00000000
3fc0: 0007a120 00018d00 00000002 0000004f 00018d8c 00018da4 40060f70 00000000
3fe0: 4005e490 be9c2048 402368e8 0000a1a0 80000010 ffffffff
Mem-info:
Normal per-cpu:
CPU    0: hi:   42, btch:   7 usd:   0
active_anon:12289 inactive_anon:9965 isolated_anon:0
active_file:258 inactive_file:338 isolated_file:0
unevictable:4255 dirty:0 writeback:0 unstable:0
free:362 slab_reclaimable:473 slab_unreclaimable:1494
mapped:768 shmem:15670 pagetables:325 bounce:0
Normal free:1448kB min:1440kB low:1800kB high:2160kB active_anon:49156kB inactive_anon:39860kB active_file:1032kB inactive_file:1352kB unevictable:17020kB isolated(anon):0kB isolated(file):0kB present:130048kB mlocked:0kB dirty:0kB writeback:0kB mapped:3072kB shmem:62680kB slab_reclaimable:1892kB slab_unreclaimable:5976kB kernel_stack:1992kB pagetables:1300kB unstable:0kB bounce:0kB writeback_tmp:0kB pages_scanned:8923 all_unreclaimable? yes
lowmem_reserve[]: 0 0
Normal: 30*4kB 2*8kB 2*16kB 0*32kB 0*64kB 0*128kB 1*256kB 2*512kB 0*1024kB 0*2048kB 0*4096kB = 1448kB
20521 total pagecache pages
0 pages in swap cache
Swap cache stats: add 0, delete 0, find 0/0
Free swap  = 0kB
Total swap = 0kB
32768 pages of RAM
781 free pages
1553 reserved pages
1967 slab pages
7920 pages shared
0 pages swap cached

oom 很奇怪 :非阻塞分配请求, 只是单页分配请求,系统还有30页,还没有过min的红线(watermark_min=1440kB)
progpr invoked oom-killer: gfp_mask=0x201da, order=0, oom_adj=0, oom_score_adj=0
gfp_mask=0x201da =___GFP_HIGHMEM|GFP_MOVABLE|GFP_WAIT|~GFP_HIGH   |___GFP_FS|___GFP_COLD|GFP_HARDWALL
Normal: 30*4kB 2*8kB 2*16kB 0*32kB 0*64kB 0*128kB 1*256kB 2*512kB 0*1024kB 0*2048kB 0*4096kB = 1448kB
   

论坛徽章:
20
程序设计版块每日发帖之星
日期:2015-08-17 06:20:00程序设计版块每日发帖之星
日期:2016-07-16 06:20:00程序设计版块每日发帖之星
日期:2016-07-18 06:20:00每日论坛发贴之星
日期:2016-07-18 06:20:00黑曼巴
日期:2016-12-26 16:00:3215-16赛季CBA联赛之江苏
日期:2017-06-26 11:05:5615-16赛季CBA联赛之上海
日期:2017-07-21 18:12:5015-16赛季CBA联赛之青岛
日期:2017-09-04 17:32:0515-16赛季CBA联赛之吉林
日期:2018-03-26 10:02:16程序设计版块每日发帖之星
日期:2016-07-15 06:20:0015-16赛季CBA联赛之江苏
日期:2016-07-07 18:37:512015亚冠之萨济拖拉机
日期:2015-08-17 12:21:08
8 [报告]
发表于 2015-03-13 14:54 |只看该作者
本帖最后由 nswcfd 于 2015-03-13 14:58 编辑

free=1448k=362 page, min=1440k=360 page,跟min watermark差不多很靠近了。

low=450 page, zone->all_unrecalimable=yes(这意思着尝试回收将失败).

毕竟计算zone_watermark_ok(min)跟打印out_of_memory之间有一些时间窗口,也许有其它上下文在这期间释放了几个page?

论坛徽章:
1
拜羊年徽章
日期:2015-03-03 16:15:43
9 [报告]
发表于 2015-03-14 11:48 |只看该作者
本帖最后由 linuxfellow 于 2015-03-15 23:11 编辑

回复 8# nswcfd
有道理,
但是在oom之前为什么没有用NO_WATERMARK再试一次。空闲空间还有1.4兆,NO WATERMARK肯定会成功。

看了最新代码,无水印只用于很特殊的情况:
请求没有指定__GFP_NOMEMALLOC
     如果请求指定__GFP_MEMALLOC
     如果在软中断服务进程,进程指定__GFP_MEMALLOC
     如果不在中断上下文,进程指定__GFP_MEMALLOC,或者进程设置了TIF_MEMDIE
             直接进行无水印分配
if (likely(!(gfp_mask & __GFP_NOMEMALLOC))) {
         if (gfp_mask & __GFP_MEMALLOC)
                 alloc_flags |= ALLOC_NO_WATERMARKS;
         else if (in_serving_softirq() && (current->flags & PF_MEMALLOC))
                 alloc_flags |= ALLOC_NO_WATERMARKS;
         else if (!in_interrupt() &&
                         ((current->flags & PF_MEMALLOC) ||
                          unlikely(test_thread_flag(TIF_MEMDIE))))
                 alloc_flags |= ALLOC_NO_WATERMARKS;
}




   

论坛徽章:
1
拜羊年徽章
日期:2015-03-03 16:15:43
10 [报告]
发表于 2015-03-16 00:07 |只看该作者
本帖最后由 linuxfellow 于 2015-03-16 05:46 编辑

仔细看了一下内存分配过程。这里的情况应该会用watermark_min/2再分配一次。但是好像没有这么做。

申请2^order内存, 提供内存申请gfp flag:
1:page = __alloc_pages(gfp, order, zonelist);
2:调用 __alloc_pages_nodemask(gfp_mask, order, zonelist, NULL);
3:设置ALLOC_WMARK_LOW标志,水印用watermark_low
      alloc_flags = ALLOC_WMARK_LOW|ALLOC_CPUSET|ALLOC_FAIR;
     调用_page_from_freelist, 需要 gfp_mask|__GFP_HARDWALL和alloc_flags
     page = get_page_from_freelist(gfp_mask|__GFP_HARDWALL, nodemask, order,
                zonelist, high_zoneidx, alloc_flags,
                preferred_zone, classzone_idx, migratetype);

4:如果分配失败,去掉IO,和FS有关的标志
     flags &= ~(__GFP_IO | __GFP_FS);
    用新的标志,调用__alloc_pages_slowpath进行分配
    page = __alloc_pages_slowpath(gfp_mask, order,
                        zonelist, high_zoneidx, nodemask,
                        preferred_zone, classzone_idx, migratetype);
      水印调整为watermark_low
5: 如果gfp_mask不禁止kswpd,启动kswpd进行回收
      if (!(gfp_mask & __GFP_NO_KSWAPD))
                wake_all_kswapds(order, zonelist, high_zoneidx,
                             preferred_zone, nodemask);
6: 加大力度,设置__GFP_HIGH,watermark_min会降到原来的一半
      alloc_flags |= (__force int) (gfp_mask & __GFP_HIGH);

7: 对于非阻塞内存请求:
     如果请求没有特殊指名__GFP_NOMEMALLOC, 进一步加大力度,设置ALLOC_HARDER。watermark_min会降到原来的1/4
     if (!(gfp_mask & __GFP_NOMEMALLOC))
                       alloc_flags |= ALLOC_HARDER;
     对于阻塞内存请求,如果是实时进程,且不在中断上下文,也设置ALLOC_HARDER
    (unlikely(rt_task(current)) && !in_interrupt())
         alloc_flags |= ALLOC_HARDER;

8:如果请求没有指定__GFP_NOMEMALLOC
     如果有指定__GFP_MEMALLOC
     如果在软中断服务进程,且进程指定__GFP_MEMALLOC
     如果不在中断上下文,且进程指定__GFP_MEMALLOC,或者进程设置了TIF_MEMDIE
             直接进行无水印分配
     if (likely(!(gfp_mask & __GFP_NOMEMALLOC))) {
         if (gfp_mask & __GFP_MEMALLOC)
                 alloc_flags |= ALLOC_NO_WATERMARKS;
         else if (in_serving_softirq() && (current->flags & PF_MEMALLOC))
                 alloc_flags |= ALLOC_NO_WATERMARKS;
         else if (!in_interrupt() &&
                         ((current->flags & PF_MEMALLOC) ||
                          unlikely(test_thread_flag(TIF_MEMDIE))))
                 alloc_flags |= ALLOC_NO_WATERMARKS;
}

9:先去掉无水印标志,加大力度正常分配再试一次
     /* This is the last chance, in general, before the goto nopage. */
     page = get_page_from_freelist(gfp_mask, nodemask, order, zonelist,
                   high_zoneidx, alloc_flags & ~ALLOC_NO_WATERMARKS,
                   preferred_zone, classzone_idx, migratetype)
10: 单独处理无水印分配,如果gfp_mask含有__GFP_NOFAIL,进入睡眠,这个过程就一直循环下去
       page = get_page_from_freelist(gfp_mask, nodemask, order,
                zonelist, high_zoneidx, ALLOC_NO_WATERMARKS,
           preferred_zone, classzone_idx, migratetype);

11: 运用前面的标志直接回收内存,direct compact主要处理大页分配,这里关系不大
      page = __alloc_pages_direct_compact(gfp_mask, order, zonelist,
                            high_zoneidx, nodemask, alloc_flags,
                                  preferred_zone,
                                  classzone_idx, migratetype,
                                  migration_mode, &contended_compaction,
                                  &deferred_compaction);

12:  直接回收。。。。。
/* Try direct reclaim and then allocating */
page = __alloc_pages_direct_reclaim(gfp_mask, order,
                                 zonelist, high_zoneidx,
                                 nodemask,
                                 alloc_flags, preferred_zone,
                                 classzone_idx, migratetype,
                                 &did_some_progress);
if (page)
         goto got_pg;

/* Check if we should retry the allocation */
pages_reclaimed += did_some_progress;
if (should_alloc_retry(gfp_mask, order, did_some_progress,
                                         pages_reclaimed)) {
         /*
          * If we fail to make progress by freeing individual
          * pages, but the allocation wants us to keep going,
          * start OOM killing tasks.
          */
         if (!did_some_progress) {
                 page = __alloc_pages_may_oom(gfp_mask, order, zonelist,
                                         high_zoneidx, nodemask,
                                         preferred_zone, classzone_idx,
                                         migratetype,&did_some_progress);
                 if (page)
                         goto got_pg;
                 if (!did_some_progress)
                         goto nopage;
         }
         /* Wait for some write requests to complete then retry */
         wait_iff_congested(preferred_zone, BLK_RW_ASYNC, HZ/50);
         goto retry;
} else {
         /*
          * High-order allocations do not necessarily loop after
          * direct reclaim and reclaim/compaction depends on compaction
          * being called after reclaim so call directly if necessary
          */
         page = __alloc_pages_direct_compact(gfp_mask, order, zonelist,
                                 high_zoneidx, nodemask, alloc_flags,
                                 preferred_zone,
                                 classzone_idx, migratetype,
                                 migration_mode, &contended_compaction,
                                 &deferred_compaction);
         if (page)
                 goto got_pg;
}

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP