问题背景
客户使用蓝牙a2dp source功能,连接蓝牙耳机播放音乐高概率出现播放无声的现象。
但在客户使用相同btmanager版本的其他机型上并没有遇到这个问题。
问题描述
在出现播放无声问题时,btmanager会一直出现如下的打印:
- <span class="hljs-section">BTMG[aw_pcm_open:400]: --->Couldn't open PCM:bluealsa:DEV=28:37:13:3B:DA:78</span>
- <span class="hljs-section">BTMG[_a2dp_src_pcm_write:150]: a2dp source open pcm error: Out of memory;</span>
复制代码
从log来看,播放时没有成功打开蓝牙虚拟声卡,所以播放没有声音是必然的。其中打开蓝牙声卡是使用标准函数snd_pcm_open,而错误信息是 Out of memory。显然从日志来看,此问题与系统内存有关系。客户机器是512M内存。
问题分析 既然与内存有关系,便从内存方向去分析此问题: 1)查看当前内存信息
cat /proc/meminfo
但是看内存信息,在声卡一直打不开的时候,MemFree也有 10M左右,所以就觉得有点奇怪了,为什么内存这么多,还是申请不到内存打开声卡呢?难道是脏内存太多了?
2)尝试线程的栈调大 - 把btmanager里面相关的线程栈调高至20K,还是无效。
- 修改C库把默认线程的栈修改为1M,依然无效。
3)清理缓存 是不是脏内存太多,内存不连续?
使用echo 3 > /proc/sys/vm/drop_caches 清理一下,发现就可以正常申请了。
但是让内存的同事看了下连续内存还是足够的,所以这还不是根本原因。
4)跟踪代码
通过在alsa-lib 里面增加打印,最终发现是在snd_user_file函数里面调用wordexp(file, &we, WRDE_NOCMD);
返回了WRDE_NOSPACE,而打开的file /usr/share/alsa/alsa.conf也只有10K左右。再继续跟踪C库里面的wordexp函数,发现是在fork的时候有问题。
接着又做了个实验,同时在出问题的时候,我们在非打开声卡的地方调用fork函数,也是会申请不到内存。
所以本质上是fork函数导致的,打开声卡的过程刚好触发了这个问题。
解决办法 对于fork函数,有如下的行为: fork函数会创建带有独立虚拟地址空间的新进程,内核会把当前进程的虚拟内存中数据结构复制一份给新进程。
看了下客户应用的出问题时的内存情况:
异常时,应用的VmPeak和VmSize偏高,这个说明此时应用申请的虚拟内存是非常高了。
此时如果有打开声卡,触发fork的操作,子进程也需要申请那么大的虚拟内存。
问题就在此,突然申请那么大的虚拟内存,被内核限制了。
解决方案: 1、客户出问题的方案,由于跑特殊的算法导致使用了比较大的虚拟内存。
可以通过优化应用内存解决。
2、取消内核的限制
在系统启动脚本加上 echo > 1 /proc/sys/vm/overcommit_memory 这个命令操作。
内核就不会限制应用申请比较大的虚拟内存了。
|