棋子 · 2022年01月02日

全志R329如何解决蓝牙播放无声(snd_pcm_open error: Out of memory)?

全志R329如何解决蓝牙播放无声(snd_pcm_open error: Out of memory)?

1 个回答 得票排序 · 时间排序
极术小姐姐 · 2022年01月04日
本回答来源全志R329如何解决蓝牙播放无声(snd_pcm_open error: Out of memory)?

问题背景
客户使用蓝牙a2dp source功能,连接蓝牙耳机播放音乐高概率出现播放无声的现象。
但在客户使用相同btmanager版本的其他机型上并没有遇到这个问题。

问题描述
在出现播放无声问题时,btmanager会一直出现如下的打印:

BTMG[aw_pcm_open:400]:  --->Couldn't open PCM:bluealsa:DEV=28:37:13:3B:DA:78
BTMG[_a2dp_src_pcm_write:150]:  a2dp source open pcm error: Out of memory;

从log来看,播放时没有成功打开蓝牙虚拟声卡,所以播放没有声音是必然的。其中打开蓝牙声卡是使用标准函数snd_pcm_open,
而错误信息是 Out of memory。显然从日志来看,此问题与系统内存有关系。客户机器是512M内存。

问题分析

既然与内存有关系,便从内存方向去分析此问题:

1)查看当前内存信息
cat /proc/meminfo
image.png
但是看内存信息,在声卡一直打不开的时候,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函数会创建带有独立虚拟地址空间的新进程,内核会把当前进程的虚拟内存中数据结构复制一份给新进程。

看了下客户应用的出问题时的内存情况:
image.png

异常时,应用的VmPeak和VmSize偏高,这个说明此时应用申请的虚拟内存是非常高了。
此时如果有打开声卡,触发fork的操作,子进程也需要申请那么大的虚拟内存。
问题就在此,突然申请那么大的虚拟内存,被内核限制了。

解决方案

1、客户出问题的方案,由于跑特殊的算法导致使用了比较大的虚拟内存。
可以通过优化应用内存解决。

2、取消内核的限制
在系统启动脚本加上 echo > 1 /proc/sys/vm/overcommit_memory 这个命令操作。
内核就不会限制应用申请比较大的虚拟内存了。

你的回答
关注数
1
收藏数
0
浏览数
2723
极术小姐姐
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息