国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

深入淺出Android同步屏障機(jī)制

這篇具有很好參考價(jià)值的文章主要介紹了深入淺出Android同步屏障機(jī)制。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

原文鏈接 Android Sync Barrier機(jī)制

詭異的假死問(wèn)題

前段時(shí)間,項(xiàng)目上遇到了一個(gè)假死問(wèn)題,隨機(jī)出現(xiàn),無(wú)固定復(fù)現(xiàn)規(guī)律,大量頻繁隨機(jī)操作后,便會(huì)出現(xiàn)假死,整個(gè)應(yīng)用無(wú)法操作,不會(huì)響應(yīng)事件,會(huì)發(fā)生各種奇怪的ANR,且trace不固定。非常之詭異。

經(jīng)過(guò)大量的復(fù)現(xiàn)研究和分析, 以及大神的指點(diǎn)后,發(fā)現(xiàn)與同步屏障(Sync Barrier)有關(guān)系,于是發(fā)現(xiàn)有必要研究一下這個(gè)東西。

深入淺出Android同步屏障機(jī)制,Android,android,Android,android runtime

什么是Sync Barrier機(jī)制

這是安卓線程消息隊(duì)列里面的一個(gè)新增加的東西,這么說(shuō)還是太抽象,我們從頭說(shuō)起這件事情:

安卓的消息隊(duì)列機(jī)制

消息隊(duì)列,或者叫做Event Loop,通常在任何一個(gè)GUI應(yīng)用程序里面都會(huì)有的,應(yīng)用大部分時(shí)間處于Idle狀態(tài),當(dāng)有事件發(fā)生時(shí),比如用戶點(diǎn)了一個(gè)button,然后開始響應(yīng)此事件。安卓也是一個(gè)GUI應(yīng)用程序,絕大多數(shù)都是帶有GUI的應(yīng)用程序,那么安卓 里面是如何實(shí)現(xiàn)這個(gè)EventLoop的呢,它是用Looper和MessageQueue,以及Handler,以一種消息隊(duì)列的方式來(lái)實(shí)現(xiàn)loop。

有一定經(jīng)驗(yàn)的同學(xué)對(duì)這些東西肯定不陌生,因?yàn)樗鼈冊(cè)趯?shí)際的開發(fā)過(guò)程中相當(dāng)常見,比如說(shuō)對(duì)于UI的操作只能放在主線程里面,那么當(dāng)工作線程想要更新UI時(shí)就需要用Handler發(fā)一個(gè)消息,或者post一個(gè)Runnable?;蛘弋?dāng)你想延后一段時(shí)間執(zhí)行某種操作,就可以用postDelayed。這些都是非常常規(guī)的操作了。對(duì)于工作線程,如果想啟用消息隊(duì)列,就用Looper#prepare就可以了,當(dāng)然了,要記得quit。

內(nèi)部原理上面也不是很復(fù)雜,就是Looper會(huì)給線程綁定一個(gè)消息隊(duì)列,即是MessageQueue,這是一個(gè)無(wú)限循環(huán)的隊(duì)列,不斷的輪詢隊(duì)列,當(dāng)有新的消息時(shí)就去處理,否則就等待。主線程,安卓框架層在創(chuàng)建應(yīng)用進(jìn)程的時(shí)候就會(huì)給主線程默認(rèn)創(chuàng)建好MessageQueue,所以就可以向其發(fā)消息(sendMessage)或者postDelayed,它們本質(zhì)上都是一樣的,都是向MessageQueue中入隊(duì)一個(gè)消息,稍后它便會(huì)得到處理。

深入淺出Android同步屏障機(jī)制,Android,android,Android,android runtime

同步消息與異步消息

這個(gè)MessageQueue機(jī)制,就是隊(duì)列,也就是說(shuō)符合隊(duì)列的特點(diǎn),先進(jìn)先出(FIFO,F(xiàn)irst-In First Out),就是說(shuō)你先post的消息,肯定是先被處理,后post的后處理,即使有delay時(shí)候,也是看誰(shuí)先到,誰(shuí)先到誰(shuí)先被處理。因此,這里面的消息全是同步,也就是說(shuō)所有消息都是順序處理,這就是同步消息。

異步消息,也就是說(shuō)某個(gè)消息,想被最高優(yōu)先級(jí)處理,無(wú)視發(fā)送消息的時(shí)機(jī),比如說(shuō)隊(duì)列里面有8個(gè)消息,如何想讓某個(gè)消息最先被處理?這時(shí)隊(duì)列就變成了優(yōu)先隊(duì)列,有優(yōu)先級(jí)的隊(duì)列。那么具有高優(yōu)先級(jí)的消息也是異步消息(Asynchronous Message)。即使是最后加入隊(duì)列的,但因?yàn)槭钱惒较ⅲ鼤?huì)被先處理,并不是FIFO,此可理解 為異步。

Sync Barrier用以實(shí)現(xiàn)優(yōu)先隊(duì)列

說(shuō)了這么多,Sync Barrier就是安卓 內(nèi)部用以實(shí)現(xiàn)優(yōu)先級(jí)隊(duì)列的一種方式。

當(dāng)隊(duì)列中出現(xiàn)Sync barrier(具體實(shí)現(xiàn)上就是Message#target為null)時(shí),就會(huì)忽略所有同步消息,尋找異步消息(isAsynchrouns為true)的消息,然后優(yōu)先處理它。

需要注意的是,把消息標(biāo)記為異步,以及向消息隊(duì)列中發(fā)送Sync barrier,這些API全部都是hide的,也就是說(shuō)app中是無(wú)法使用的,通過(guò)反射也許能調(diào)用成功,但風(fēng)險(xiǎn)也較大,后續(xù)會(huì)被谷歌限制調(diào)用。換言之,這東西只能在Frameworks層內(nèi)部自己使用。

為什么要有Sync Barrier

說(shuō)了這么多,其實(shí)本質(zhì)上,這東西就是一個(gè)優(yōu)先隊(duì)列,給要處理的消息加一個(gè)優(yōu)先級(jí)機(jī)制,那這有什么實(shí)際用途呢?

消息隊(duì)列這東西是在安卓一誕生就有了的東西,大部分時(shí)候它也沒有什么問(wèn)題。但有一個(gè)事情,就是安卓操作系統(tǒng)的UI流暢度遠(yuǎn)不及水果平臺(tái)(iOS),原因就是在于水果平臺(tái)的UI渲染是整個(gè)系統(tǒng)中最高優(yōu)先執(zhí)行。

有同學(xué)會(huì)說(shuō)安卓里面也是這樣啊,你想U(xiǎn)I都只能在主線程里面操作(因此主線程也叫UI線程)。只能在主線程中操作UI,就能保證UI渲染是最高優(yōu)先級(jí)嗎?當(dāng)然不是了。因?yàn)檎麄€(gè)應(yīng)用程序的默認(rèn)線程就是主線程,換句話說(shuō),如果你不明顯的去做線程切換,或者啟用工作線程,那么所有事情都發(fā)生在主線程里面,當(dāng)然 也包括了UI渲染,因此UI的渲染與你在主線程時(shí)面post一個(gè)消息的優(yōu)先級(jí)是一樣的。

如何讓UI渲染在主線程中以最高優(yōu)先級(jí)運(yùn)行?于是就有了Sync barrier機(jī)制,這東西就是為了讓消息隊(duì)列有優(yōu)先級(jí),并且沒有開放給app使用??梢匀タ匆幌耉iewRootImpl(這貨是專門負(fù)責(zé)ViewTree渲染的,也即可以理解為負(fù)責(zé)UI渲染的)的幾個(gè)perform,它都是異步消息,也即會(huì)開啟Sync barrier,它發(fā)送的消息將會(huì)是最高優(yōu)先級(jí)的,會(huì)被優(yōu)先處理。

主要在哪里用Sync barrier

前面提到了,Sync barrier這玩意兒并不是給app開發(fā)同學(xué)用的,很多相關(guān)的接口并沒有開放出來(lái),這是為了提高UI渲染而設(shè)計(jì)的東西。因此這東西主要是用在了UI渲染過(guò)程中。

仔細(xì)查看ViewRootImpl的源碼可以發(fā)現(xiàn),每次渲染View tree之前都會(huì)先給主線程插入一個(gè)Sync barrier,以擋住同步消息,以保證渲染被主線程優(yōu)先執(zhí)行到。

    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    void scheduleTraversals() {
        if (!mTraversalScheduled) {
            mTraversalScheduled = true;
            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
            mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
            notifyRendererOfFramePending();
            pokeDrawLockIfNeeded();
        }
    }

    void unscheduleTraversals() {
        if (mTraversalScheduled) {
            mTraversalScheduled = false;
            mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
            mChoreographer.removeCallbacks(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
        }
    }

    void doTraversal() {
        if (mTraversalScheduled) {
            mTraversalScheduled = false;
            mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);

            performTraversals();
       }
    }

這里的邏輯略復(fù)雜一些,View tree本身的處理過(guò)程,也即三大步measure, layout和draw,也就是performTraversal本身并沒有異步消息,它是在準(zhǔn)備渲染的時(shí)候放一個(gè)sync barrier,而在具體處理每一幀前就移除了sync barrier,這里為何要這樣,還沒有完全想清楚。通過(guò)搜索ViewRootImpl可以發(fā)現(xiàn)只有input event,keyevent 以及與用戶輸入相關(guān)的消息被設(shè)置為了asynchronous,也就是說(shuō)用戶事件響應(yīng)被提高了優(yōu)先級(jí),而view tree的渲染,即UI的每一幀,其實(shí)并沒有被提升優(yōu)先級(jí)。因?yàn)閁I刷的每一幀是以固定頻率刷新的,Choreographer 從硬件得到vsync脈沖信號(hào),然后回調(diào)給ViewRootImpl讓其渲染每一幀(也即是performTraversal)。

Sync Barrier會(huì)引發(fā)什么問(wèn)題

說(shuō)實(shí)話,這套機(jī)制,實(shí)現(xiàn)的并不怎么優(yōu)雅,因?yàn)?,畢竟它并不是在最初的設(shè)計(jì)之初就考慮到的東西,它的整體運(yùn)行機(jī)制并不完善,非常依賴于調(diào)用者的使用,所以它的相關(guān)API并未有開放出來(lái)。

它有三步,先發(fā)一個(gè)Sync barrier,然后發(fā)送異步消息,然后再移除Sync barrier。

只有UI渲染(ViewTree的相關(guān)操作,才需要這樣做),大部分其他的消息都是同步的,并不需要這樣搞。當(dāng)有Sync barrier時(shí),消息隊(duì)列在處理消息的時(shí)候會(huì)忽略掉所有的同步消息(也即是常規(guī)消息),優(yōu)先處理異步消息,直到Sync barrier移除,也是需要手動(dòng)移除的。Sync barrier需要手動(dòng)移除是最坑的。

因此,假如要處理的異步特別多,或者邏輯出錯(cuò)Sync barrier沒有被移除,那就悲劇 了,就會(huì)導(dǎo)致消息隊(duì)列中的大量常規(guī)消息無(wú)法得到處理,隊(duì)列就會(huì)停止工作,應(yīng)用會(huì)出現(xiàn)隨機(jī)的ANR,以及假死。

如何調(diào)試

很不幸,Sync barrier導(dǎo)致的問(wèn)題很難調(diào)試,甚至很難被發(fā)現(xiàn),通常都是ANR或者說(shuō)卡死問(wèn)題。

那么首先可以按照ANR和卡死的常規(guī)分析方式去分析,假如都未發(fā)現(xiàn)明顯的問(wèn)題時(shí),比如沒有明顯的耗時(shí)的操作,也沒有死鎖,也沒有被硬件和IO阻塞,也沒有進(jìn)入死循環(huán)。

這些常規(guī)的分析,都沒有發(fā)現(xiàn)問(wèn)題。這時(shí)就可以考慮是不是Sync barrier在搞鬼。特別當(dāng)涉及一些詭異的UI狀態(tài)時(shí),比如某個(gè)View只顯示 了一半,比如某一個(gè)View沒有顯示 完全,比如只有背景沒有前景,等等,當(dāng)排除了其他常規(guī)問(wèn)題時(shí),就很可能是Sync barrier有異常導(dǎo)致的。

另外,如果有能力修改Frameworks的話,可以給MessageQueue增加dump信息,把隊(duì)列中的所有消息都打印出來(lái),以及把Sycn barrier也都打印出來(lái),這樣能夠比較清楚看到,隊(duì)列內(nèi)部的情況,自然也能夠發(fā)現(xiàn)異常的Sync barrier。

如何避免Sync Barrier搞鬼

前面提到過(guò),這套東西都是Frameworks層內(nèi)部的機(jī)制,并沒有開放給app使用,而Frameworks內(nèi)部的邏輯一般來(lái)說(shuō)還是相當(dāng)健壯的,絕大多數(shù)時(shí)候并不會(huì)出問(wèn)題。當(dāng)然了,各個(gè)廠商內(nèi)部搞的各種所謂優(yōu)化,倒是有可能會(huì)引發(fā)問(wèn)題。

在實(shí)際開發(fā)過(guò)程中,引發(fā)Sync barrier的最多場(chǎng)景就是自定義View。對(duì)于自定義View,是能夠在非主線程調(diào)用其invalidate的,當(dāng)有大量的非主線程調(diào)用invalidate時(shí),就有可能恰好與主線程的渲染發(fā)生交互,具體case非常corner要?jiǎng)偳煞侵骶€程在postInvalide,然后主線程也剛巧在發(fā)送異步消息,就可能使得Sync barrier沒有被移除,從而導(dǎo)致問(wèn)題。

這就需要我們?cè)诰幋a階段做好封裝,對(duì)于自定義View的刷新觸發(fā)邏輯做好封裝,做一下線程切換,以保證是在主線程里面執(zhí)行invalidate。因?yàn)楸┞冻鋈サ慕涌?,是沒有辦法控制的,你沒有辦法讓所有調(diào)用者都在主線程里面調(diào)用你的接口。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-704283.html

參考資料

  • Handler sync barrier(同步屏障)
  • Android 同步屏障機(jī)制(Sync Barrier)
  • 同步屏障?阻塞喚醒?和我一起重讀 Handler 源碼
  • 同步屏障與異步消息,從入門到放棄
  • 面試官:如何提高M(jìn)essage的優(yōu)先級(jí)
  • 今日頭條 ANR 優(yōu)化實(shí)踐系列 - Barrier 導(dǎo)致主線程假死

原創(chuàng)不易,打賞,點(diǎn)贊,在看,收藏,分享 總要有一個(gè)吧

到了這里,關(guān)于深入淺出Android同步屏障機(jī)制的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Android:同步屏障的簡(jiǎn)單理解和使用

    Android:同步屏障的簡(jiǎn)單理解和使用

    這里我們假設(shè)一個(gè)場(chǎng)景:我們向主線程發(fā)送了一個(gè)UI繪制操作Message,而此時(shí)消息隊(duì)列中的消息非常多,那么這個(gè)Message的處理可能會(huì)得到延遲,繪制不及時(shí)造成界面卡頓。同步屏障機(jī)制的作用,是讓這個(gè)繪制消息得以越過(guò)其他的消息,優(yōu)先被執(zhí)行。 Handler的message分為三種 同步

    2024年02月08日
    瀏覽(37)
  • Spring高手之路14——深入淺出:SPI機(jī)制在JDK與Spring Boot中的應(yīng)用

    Spring高手之路14——深入淺出:SPI機(jī)制在JDK與Spring Boot中的應(yīng)用

    ?? SPI ( Service Provider Interface ) 是一種服務(wù)發(fā)現(xiàn)機(jī)制,它允許第三方提供者為核心庫(kù)或主框架提供實(shí)現(xiàn)或擴(kuò)展。這種設(shè)計(jì)允許核心庫(kù)/框架在不修改自身代碼的情況下,通過(guò)第三方實(shí)現(xiàn)來(lái)增強(qiáng)功能。 JDK原生的SPI : 定義和發(fā)現(xiàn) : JDK 的 SPI 主要通過(guò)在 META-INF/services/ 目錄下放置

    2024年02月09日
    瀏覽(26)
  • 深入理解Android音視頻同步機(jī)制(一)ExoPlayer的avsync邏輯

    深入理解Android音視頻同步機(jī)制(一)ExoPlayer的avsync邏輯

    對(duì)于此前沒有了解過(guò)ExoPlayer的朋友,我們?cè)谶@里先用下面的時(shí)序圖簡(jiǎn)單介紹一下ExoPlayer在音視頻同步這塊的基本流程: 圖中 ExoPlayerImplInternal是Exoplayer的主loop所在處,這個(gè)大loop不停的循環(huán)運(yùn)轉(zhuǎn),將下載、解封裝的數(shù)據(jù)送給AudioTrack和MediaCodec去播放。 MediaCodecAudioRenderer和MediaC

    2023年04月12日
    瀏覽(20)
  • 【深入淺出RocketMQ原理及實(shí)戰(zhàn)】「底層原理挖掘系列」透徹剖析貫穿RocketMQ的消息消費(fèi)長(zhǎng)輪訓(xùn)機(jī)制體系的原理分析

    使用系統(tǒng)控制讀取操作的DefaultMQPushConsumer可以自動(dòng)調(diào)用傳入的處理方法來(lái)處理收到的消息。通過(guò)設(shè)置各種參數(shù)和傳入處理消息的函數(shù),使用DefaultMQPushConsumer的主要目的是方便配置和處理消息。在收到消息后,系統(tǒng)會(huì)自動(dòng)保存Offset,并且如果加入了新的DefaultMQPushConsumer,系統(tǒng)會(huì)

    2024年02月11日
    瀏覽(22)
  • 【深入淺出RocketMQ原理及實(shí)戰(zhàn)】「底層原理挖掘系列」透徹剖析貫穿RocketMQ的消息順序消費(fèi)和并發(fā)消費(fèi)機(jī)制體系的原理分析

    【深入淺出RocketMQ原理及實(shí)戰(zhàn)】「底層原理挖掘系列」透徹剖析貫穿RocketMQ的消息順序消費(fèi)和并發(fā)消費(fèi)機(jī)制體系的原理分析

    首先, DefaultMQPushConsumerImpl 是一個(gè)實(shí)現(xiàn)了 RocketMQ 的消費(fèi)者客戶端接口的類。該類的主要作用是從 RocketMQ 的 Broker 獲取消息并進(jìn)行消費(fèi)。 主要可以通過(guò)pullMessage方法進(jìn)行獲取對(duì)應(yīng)的操作,如下圖所示。 在消費(fèi)消息時(shí), DefaultMQPushConsumerImpl 會(huì)將獲取到的消息放入一個(gè) processQueue

    2024年02月11日
    瀏覽(26)
  • 深度學(xué)習(xí)深入淺出

    目錄 一 基本原理 二 深度學(xué)習(xí)的優(yōu)點(diǎn) 三 深度學(xué)習(xí)的缺點(diǎn) 四 深度學(xué)習(xí)應(yīng)用 手寫數(shù)字識(shí)別 深度學(xué)習(xí)是機(jī)器學(xué)習(xí)的一個(gè)分支,其核心思想是利用深層神經(jīng)網(wǎng)絡(luò)對(duì)數(shù)據(jù)進(jìn)行建模和學(xué)習(xí),從而實(shí)現(xiàn)識(shí)別、分類、預(yù)測(cè)等任務(wù)。在過(guò)去幾年中,深度學(xué)習(xí)技術(shù)取得了許多突破性的成果,如

    2023年04月09日
    瀏覽(27)
  • 深入淺出線程池

    線程 (thread)是操作系統(tǒng)能夠進(jìn)行運(yùn)算調(diào)度的最小單位。它被包含在進(jìn)程之中,是進(jìn)程中的實(shí)際 運(yùn)作單位。一條線程指的是進(jìn)程中一個(gè)單一順序的控制流,一個(gè)進(jìn)程中可以并發(fā)多個(gè)線程,每條線 程并行執(zhí)行不同的任務(wù)。 既然我們創(chuàng)建了線程,那為何我們直接調(diào)用方法和我們調(diào)

    2024年02月08日
    瀏覽(24)
  • 隨機(jī)森林算法深入淺出

    目錄 一 隨機(jī)森林算法的基本原理 二 隨機(jī)森林算法的優(yōu)點(diǎn) 1. 隨機(jī)森林算法具有很高的準(zhǔn)確性和魯棒性 2. 隨機(jī)森林算法可以有效地避免過(guò)擬合問(wèn)題 3. 隨機(jī)森林算法可以處理高維度數(shù)據(jù) 4. 隨機(jī)森林算法可以評(píng)估特征的重要性 三 隨機(jī)森林算法的缺點(diǎn) 1. 隨機(jī)森林算法對(duì)于少量數(shù)

    2023年04月08日
    瀏覽(26)
  • 深入淺出IAM(1)

    深入淺出IAM(1)

    在本人即將入職的一份基礎(chǔ)架構(gòu)的工作前,我提前聯(lián)系到了團(tuán)隊(duì)leader并跟他進(jìn)行了一次1-1。談話中提到了我可能會(huì)先上手的一個(gè)項(xiàng)目是IAM相關(guān)的實(shí)現(xiàn),于是趁著入職前的間隙,我學(xué)習(xí)了部分優(yōu)秀開源IAM項(xiàng)目實(shí)現(xiàn)思路以及騰訊云開發(fā)專家孔老師的專欄。 在反復(fù)思考和總結(jié)提煉后

    2024年02月05日
    瀏覽(34)
  • 深入淺出前端本地儲(chǔ)存

    深入淺出前端本地儲(chǔ)存

    2021 年,如果你的前端應(yīng)用,需要在瀏覽器上保存數(shù)據(jù),有三個(gè)主流方案: Cookie Web Storage (LocalStorage) IndexedDB 這些方案就是如今應(yīng)用最廣、瀏覽器兼容性最高的三種前端儲(chǔ)存方案 今天這篇文章就聊一聊這三種方案的歷史,優(yōu)缺點(diǎn),以及各自在今天的適用場(chǎng)景 文章在后面還會(huì)提

    2024年04月17日
    瀏覽(28)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包