记录一次解决native内存泄漏的心理历程

一、概述

调试ffmpeg的stop方法时,需要等待decode解码线程执行完成:

    // 更新队列的工作状态,并唤醒阻塞中(wait)的线程
    packets.setWork(0); 
    frames.setWork(0);
    LOGE("AudioChannel::stop() pthread_join(pid_audio_decode,0)");
    // 等待pid_audio_decode的线程执行完毕
    pthread_join(pid_audio_decode,0);
    ......

然而调试时发现,卡在join这句不往下走了。

二、分析

预估是pid_audio_decode线程阻塞了,于是分析其代码片段:

void AudioChannel::decode() {
    AVPacket *packet = 0;
    LOGE("AudioChannel::decode begin");
    while (isPlaying){
        LOGE("AudioChannel::decode loop isPlaying = %d", isPlaying);
        // 取出一个数据包
        LOGE("AudioChannel::decode packets.pop(packet)");
        int ret = packets.pop(packet);
        if (!isPlaying){
            break;
        }
        if (!ret){
            continue;
        }
       ......
    }
}

通过log分析,while循环卡在这句 packets.pop(packet)了,再深入队列的pop()方法:

// 传递引用参数是为了修改它的值;用入参作为返回值可以返回多个(T& t1, T& t2...)
    int pop(T& value){
        int ret = 0;
        pthread_mutex_lock(&mutex);
        // 在多核处理器下 由于竞争可能虚假唤醒 包括jdk也说明了
        while (q.empty()){
            // 没有数据就等待
            LOGE("pop : pthread_cond_wait");
            pthread_cond_wait(&cond, &mutex);
        }
        if (!q.empty()){
            value = q.front();
            q.pop();
            ret = 1;
        }
        LOGE("pop : pthread_mutex_unlock");
        pthread_mutex_unlock(&mutex);
        return ret;
    }

有没有发现什么问题?如果队列q一直为空,即使通过条件变量通知唤醒wait操作,还是会一直循环下去,造成死循环,也就会阻塞其所在的线程,这就是pid_audio_decode线程阻塞的原因了。

三、解决方案

由于队列里面已经定义了一个是否工作的标记,可以用它来控制队列的同步操作

// 是否工作的标记 1 :工作 0:不接受数据 不工作
    int work;

pop()方法优化如下:

int pop(T& value){
        int ret = 0;
        pthread_mutex_lock(&mutex);
        // 在多核处理器下 由于竞争可能虚假唤醒 包括jdk也说明了
        // 添加work判断,如果不工作了直接跳出循环,否则会一直wait造成死循环,从而阻塞线程
        while (work && q.empty()){
            // 没有数据就等待
            LOGE("pop : pthread_cond_wait");
            pthread_cond_wait(&cond, &mutex);
        }
        if (!q.empty()){
            value = q.front();
            q.pop();
            ret = 1;
        }
        LOGE("pop : pthread_mutex_unlock");
        pthread_mutex_unlock(&mutex);
        return ret;
    }

这样优化之后,如果想要停止队列的操作,可以预先设定work标记为0,则可以避免进入死循环了。


双鱼座黄金圣斗士神圣衣
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 1.ios高性能编程 (1).内层 最小的内层平均值和峰值(2).耗电量 高效的算法和数据结构(3).初始化时...
    欧辰_OSR阅读 29,643评论 8 265
  • 教程一:视频截图(Tutorial 01: Making Screencaps) 首先我们需要了解视频文件的一些基...
    90后的思维阅读 4,792评论 0 3
  • 本文是我自己在秋招复习时的读书笔记,整理的知识点,也是为了防止忘记,尊重劳动成果,转载注明出处哦!如果你也喜欢,那...
    波波波先森阅读 11,334评论 4 56
  • 1.四川成都和重庆山城辣的区别 离开南方,最遗憾莫过于从此食无川辣。 很多人分不清四川和重庆的辣区别于何,自古巴蜀...
    唐诗远阅读 1,121评论 6 4
  • 抱歉,标题党了。其实又回到了读书笔记。(你来咬我呀) 自打参加了拆书帮这个神秘组织,对带“拆”字的东西总是倍感兴趣...
    菲妮阅读 339评论 0 1