Android bug——hwui中fb socket泄露问题

现象描述:
在launcher的使用过程中,会发现系统越来越慢,内存越来越少,通过adb shell ps -t可以查看到当前launcher开启了几百上千个线程,这样就导致了系统越来越慢。
分析:

通过定位,发现在hwui中,当绘制带阴影的字体的时候,使用了renderScript,由于renderScript中绘制阴影时,会开启3-4个线程来处理阴影文字。

void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, int32_t radius) {
#ifdef ANDROID_ENABLE_RENDERSCRIPT
    if (width * height * radius >= RS_MIN_INPUT_CUTOFF) {
        uint8_t* outImage = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, width * height);

        if (mRs == 0) {
            mRs = new RSC::RS();
            if (!mRs->init(RSC::RS_INIT_LOW_LATENCY | RSC::RS_INIT_SYNCHRONOUS)) {
                ALOGE("blur RS failed to init");
            }

            mRsElement = RSC::Element::A_8(mRs);
            mRsScript = RSC::ScriptIntrinsicBlur::create(mRs, mRsElement);
        }

        RSC::sp<const RSC::Type> t = RSC::Type::create(mRs, mRsElement, width, height, 0);
        RSC::sp<RSC::Allocation> ain = RSC::Allocation::createTyped(mRs, t,
                RS_ALLOCATION_MIPMAP_NONE, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
                *image);
        RSC::sp<RSC::Allocation> aout = RSC::Allocation::createTyped(mRs, t,
                RS_ALLOCATION_MIPMAP_NONE, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
                outImage);

        mRsScript->setRadius(radius);
        mRsScript->setInput(ain);
        mRsScript->forEach(aout);

        // replace the original image's pointer, avoiding a copy back to the original buffer
        free(*image);
        *image = outImage;

        return;
    }
#endif
当内存不足时,会调用GammaFontRenderer的clear函数,也就是会将当前的FontRenderer对象删除,由于rs对象是以智能指针的形式来使用,所以正常情况在FontRenderer的时候会将当前的rs指针对象都删除,通过写一些测试用例发现,rs使用的智能指针在析构的时候并没有将rs的对象删除,这也就是导致每次创建了rs对象没删除,导致一直会创建大量的线程的原因。

通过查看renderScript的代码,发现rs的对象都是使用强指针引用(sp)的方式来使用:

    struct {
        sp<const Element> U8;
        sp<const Element> U8_2;
        sp<const Element> U8_3;
        sp<const Element> U8_4;
        
	…………	
        sp<const Element> A_8;
        sp<const Element> RGB_565;
        sp<const Element> RGB_888;
        sp<const Element> RGBA_5551;
        sp<const Element> RGBA_4444;
        sp<const Element> RGBA_8888;
        sp<const Element> YUV;
        sp<const Element> MATRIX_4X4;
        sp<const Element> MATRIX_3X3;
        sp<const Element> MATRIX_2X2;
    } mElements;
这样导致mRsElement中使用了mRs的强引用,当mRsElement也保存了mRs的强引用,当mRsElement生命周期结束时,由于不等1,所以只能将mRsElement的引用计数减1,mRs还是为2,这样也就会导致最后出现循环引用问题,无法将任何一个对象删除,这就导致了申请的线程没有释放,出现了fb socket泄露的问题。

解决方案:
1. 临时解决方案:

将FontRenderer的rs对象都设置为静态对象,这样就能避免出现socket泄露的问题:

#ifdef ANDROID_ENABLE_RENDERSCRIPT
    // RS constructs
    static RSC::sp<RSC::RS> mRs;
    static RSC::sp<const RSC::Element> mRsElement;
    static RSC::sp<RSC::ScriptIntrinsicBlur> mRsScript;
#endif

2. 修改renderScript:

这种修改方式比较麻烦,需要将rs中存在强智能指针的对象都改为普通指针的方式,所幸的是,后面google已经在这方便做了修改,所以可以参考google官网的修改:https://android-review.googlesource.com

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值