前段时间在做播放器的时候,遇到个问题,花了很长时间,做个记录,希望对有需要的人有所帮助:

播放器的播视频的时候,无论是手动切换视频还是到视频播放完成,自动切换视频,一定次数后均出现黑屏现象,偶尔有声音,问题出现后,不可恢复,Kernel输出如下Log:

DMA free:71672kB min:616kB low:768kB high:924kB active_anon:0kB inactive_anon:0kB active_file:0kB inactive_file:0kB unevictable:0kB isolateds

lowmem_reserve[]: 0 1244 1593 1593

Normal free:1249804kB min:4212kB low:5264kB high:6316kB active_anon:0kB inactive_anon:0kB active_file:0kB inactive_file:0kB unevictable:0kB o

lowmem_reserve[]: 0 0 2794 2794

HighMem free:223000kB min:348kB low:640kB high:936kB active_anon:39248kB inactive_anon:140kB active_file:61020kB inactive_file:34108kB unevio

lowmem_reserve[]: 0 0 0 0

DMA: 22*4kB 90*8kB 21*16kB 82*32kB 7*64kB 137*128kB 69*256kB 3*512kB 8*1024kB 5*2048kB 3*4096kB 0*8192kB 0*16384kB 0*32768kB = 71672kB

Normal: 1*4kB 53*8kB 16*16kB 6*32kB 6*64kB 4*128kB 1*256kB 1*512kB 2*1024kB 2*2048kB 3*4096kB 2*8192kB 4*16384kB 35*32768kB = 1249772kB

HighMem: 14*4kB 10*8kB 437*16kB 386*32kB 374*64kB 27*128kB 10*256kB 7*512kB 8*1024kB 7*2048kB 4*4096kB 2*8192kB 1*16384kB 3*32768kB = 223000B

23829 total pagecache pages

0 pages in swap cache

Swap cache stats: add 0, delete 0, find 0/0

Free swap  = 0kB

Total swap = 0kB

524288 pages of RAM

387015 free pages

73287 reserved pages

1169 slab pages

8545 pages shared

0 pages swap cached

Physical memory allocation error!

Physical memory allocation error!

通过Log,定位到输出的位置是解码驱动中,驱动在DMA请求失败后,输出以上信息。针对这个现象,按以下几个思路进行的调查:

1. 内存泄露

在驱动中增加了一些Log,随着视频切换,分配的地址会一定程度的变大,直到最后分配失败。但仔细研究发现分配与释放是配对的,驱动中记录的内存使用信息完全正确,没有任何迹象表明有内存泄露发生。

2. 内存碎片

官论上有同样的问题登录,但无明确结论,官方应该是没重现。民间有人指出问题在于驱动请求的连续内存块比较大,但系统已无相应的内存可供分配,即内存碎片了。同时有人给出俩个方案:缓存每次的请求的内存,分配后,不再返还给系统,这个方案我测试后,发现会导致其它视频驱动出现同样问题,不可用;另一个方案是认为导致内存碎片的原因在于,文件系统的Cache机制,要解决这个问题,需要清除被Cache占用的内存,方法如下:

echo 3 > /proc/sys/vm/drop_caches

试验之后,果然有效,测试了手中的测试用例几千次后,发了测试软件,结果悲剧,开发部的测试用例几次就测出同样的问题,该方案水土不服。

3. 调查Linux内存使用

从内存碎片这个思路出发,分析什么导致了驱动的DMA空间碎片化。查了一些资料发现,Linux的内存划分分成3块:DMA,Low Memory和High Memory。一般32位PC的配置是DMA Zone位于0x00010000-0x00ffffff,大约16MB,Low Memory是0x01000000-0x37bfdfff,约800多MB,再往上的空间给High Memory,这部分的访问要通过跳转,性能不如DMA Zone和Low Memory Zone快。而内存分配的策略是从上往下分配,一旦高位的内存空间不足,则向低地址的空间请求内存。在我们的产品上,总的内存大小是512MB,某些驱动预留128MB,DMA Zone的配置是184MB,那么实际剩下的Low Memory Zone只有200MB,而这200MB要运行UI,媒体管理,互联等等一系列进程。一旦Low Memory Zone的内存不够用,系统会向DMA Zone请求内存,从而导致的DMA空间的内存碎片化!而这时,通过free命令是看不到正确的内存信息的,因为看到的空间还有,但一是被Cache占用,二是计算的是总数,而不是真正的连续内存,这时查看内存应该使用系统提供的Buddy Info来看真正剩余的内存块:

$cat /proc/buddyinfo

Node 0, zone      DMA      3      1      3      4      1      2      2      0      1      2      0      3      2      2

Node 0, zone   Normal     74     36     29      8      6      4      3      2      1      2      3      2      0      2

输出的数据从左侧开始是4K内存块的个数,依次乘2到最右侧的32M;在出问题时,系统基本上只有小块的内存,而问题的原因就是一些文件访问的操作导致DMA Zone的空间被Cache使用了。

4. 控制内存分配算法

找到问题的原因后,调查如何能禁止系统从DMA Zone分配内存。查找到可以设置lowmem_reserve_ratio,来告诉系统,DMA Zone的预留空间。其参数有3个(系统默认:256,32,32),与DMA Zone有关的是第一个,其值是除数,用DMA Zone的大小除以256,得到的基本就是预留的大小了。做了几个测试后,发现只有设置为1才能有效保护DMA Zone不被占用,:(!设置为1后,视频不再出现黑屏,但其他问题很快出现,因为系统可用的内存减少,内存的回收算法被频繁执行,性能急剧下降。

5. 最终方案

由于产品的总内存太小,而预留的DMA Zone太大,所以需要调整DMA Zone预留的空间,但lowmem_reserve_ratio已无调整空间,所以考虑从调整Kernel上下手。最后,将Kernel中的DMA Zone总大小由184MB调整为原来的3/4,即138MB,得到一个近似合理的配置,保证的DMA和Low Memory都可以申请到足够的空间,长时间测试后,未再现相关问题。

Linux内存使用调整的更多相关文章

  1. Linux内存管理原理

    本文以32位机器为准,串讲一些内存管理的知识点. 1. 虚拟地址.物理地址.逻辑地址.线性地址 虚拟地址又叫线性地址.linux没有采用分段机制,所以逻辑地址和虚拟地址(线性地址)(在用户态,内核态逻 ...

  2. Linux内存管理原理【转】

    转自:http://www.cnblogs.com/zhaoyl/p/3695517.html 本文以32位机器为准,串讲一些内存管理的知识点. 1. 虚拟地址.物理地址.逻辑地址.线性地址 虚拟地址 ...

  3. linux内存——/proc/sys/vm/drop_caches

      原贴:http://www.linuxfly.org/post/320/ http://blog.csdn.net/chinalinuxzend/article/category/265273/2 ...

  4. Windows内存管理和linux内存管理

    windows内存管理 windows 内存管理方式主要分为:页式管理,段式管理,段页式管理. 页式管理的基本原理是将各进程的虚拟空间划分为若干个长度相等的页:页式管理把内存空间按照页的大小划分成片或 ...

  5. linux 内存管理——内核的shmall 和shmmax 参数

    内核的 shmall 和 shmmax 参数 SHMMAX= 配置了最大的内存segment的大小 ------>这个设置的比SGA_MAX_SIZE大比较好. SHMMIN= 最小的内存seg ...

  6. Cgroup - Linux 内存资源管理

    Hi ,我是 Zorro .这是我的微博地址,我会不定期在这里更新文章,如果你有兴趣,可以来关注我呦. 另外,我的其他联系方式: Email: mini.jerry@gmail.com QQ: 300 ...

  7. 手工释放Linux内存

    转载自:http://blog.csdn.net/wyzxg/article/details/7279986/ linux的内存查看: [root@localhost 0.1.0]# free -m  ...

  8. linux内存基础知识和相关调优方案

    内存是计算机中重要的部件之中的一个.它是与CPU进行沟通的桥梁. 计算机中全部程序的执行都是在内存中进行的.因此内存的性能对计算机的影响很大.内存作用是用于临时存放CPU中的运算数据,以及与硬盘等外部 ...

  9. 手工释放linux内存——/proc/sys/vm/drop_caches

    --手工释放linux内存——/proc/sys/vm/drop_caches 总有很多朋友对于Linux的内存管理有疑问,之前一篇日志似乎也没能清除大家的疑虑.而在新版核心中,似乎对这个问题提供了新 ...

随机推荐

  1. HDU 1052(田忌赛马 贪心)

    题意是田忌赛马的背景,双方各有n匹马,下面两行分别是田忌和齐王每匹马的速度,要求输出田忌最大的净胜场数*每场的赌金200. 开始的时候想对双方的马匹速度排序,然后比较最快的马,能胜则胜,否则用最慢的马 ...

  2. [机器学习笔记]奇异值分解SVD简介及其在推荐系统中的简单应用

    本文先从几何意义上对奇异值分解SVD进行简单介绍,然后分析了特征值分解与奇异值分解的区别与联系,最后用python实现将SVD应用于推荐系统. 1.SVD详解 SVD(singular value d ...

  3. Dapper.net Insert mssql unicode 乱码问题

    1.效果: 2.处理方法: /// <summary> /// insert single sql /// </summary> /// <typeparam name= ...

  4. oracle 启动em (使用浏览器打开)

    在cmd命令中执行 emctl status dbconsole 如果报错,确实oracle_UNQNAME 这个时候需要设置变量 oracle_hostname 和oracle_unqname 执行 ...

  5. RHEL 6.4 通过mysql安装文件安装mysql

    参考文章:http://www.linuxidc.com/Linux/2013-12/93507.htm 1.首先下载mysql安装文件 我是下载的最新版的5.6 2. 以RPM方式安装MySQL 在 ...

  6. day 10 - 2 函数练习

    1.写函数 接收 n 个数字  求这些参数数字的和 def sum_func(*args): total = 0 for i in args: total += i return total prin ...

  7. Python基础5-常用模块

    本节大纲 模块介绍 time &datetime模块 random os sys shutil shelve xml处理 yaml处理 configparser hashlib subproc ...

  8. 基于【字符】操作的IO接口:Writer、Reader

    Reader public class BufferedReaderTest { public static void main(String[] args) throws IOException { ...

  9. 全国人口 信息(NCIIC)接口开发纪要

    阶段一:根据wsdl2java命令解析https://ws.nciic.org.cn/nciic_ws/services/NciicServices?wsdl以生成接口调用的对象类: wsdl2jav ...

  10. Hadoop环境准备

    1. 集群简介 HADOOP集群具体来说包含两个集群:HDFS集群和YARN集群,两者逻辑上分离,但物理上常在一起. HDFS集群负责海量数据的存储,集群中的角色主要有: NameNode.DataN ...