日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

分析Kotlin协程只挂起不恢复会怎样(是否存在协程泄漏),以及挂起的协程存在哪里?

發布時間:2025/3/21 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 分析Kotlin协程只挂起不恢复会怎样(是否存在协程泄漏),以及挂起的协程存在哪里? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

剛開始正式學協程原理的時候(以前只是學api怎么用),大概是20年6月,也就是bennyhuo大佬出書<深入理解Kotlin協程>的時候,我買了本然后細細研究,我的內心就一直有一個問題,協程只掛起不恢復會不會造成協程的內存和程序泄漏.

后來經過我debug和分析jvm字節碼,終于找到了答案!

正文

首先放出結論:

  • 協程只掛起不恢復只會造成一直掛起,后面的代碼塊得不到執行
  • 協程只掛起不恢復不會造成協程泄漏(前提是你沒有將協程體對象傳出去且長時間引用)
  • 掛起的協程體存在匿名內部類中
  • ps:主要的分析手段是靠分析jvm字節碼,debug算是輔助手段

    首先是需要分析的代碼:

    main {//啟動一個主線程協程"123".e2()//打印日志suspendCoroutine<Unit> { post { it.resume(Unit) } }//掛起并post到主線程之后恢復協程"5".e2()suspendCoroutine<Unit> { }//只掛起不恢復協程"456".e2()}

    編譯后的jvm字節碼再經過反編譯得到的java代碼(過濾不重要的代碼):

    啟動的代碼,封裝了launch和scope:

    public void init() {//這里就是上面的入口代碼main(this, new MainActivity$init$1((Continuation) null));}public static Job main(BaseActive $this, Function2<? super CoroutineScope, ? super Continuation<? super Unit>, ? extends Object> run) {//下面就是正常的launch流程了return BuildersKt__Builders_commonKt.launch$default($this.getMainScope(), (CoroutineContext) null, (CoroutineStart) null, run, 3, (Object) null);}

    掛起函數生成的匿名內部類,對應main方法傳入的lambda:

    final class MainActivity$init$1 extends SuspendLambda implements Function2<CoroutineScope, Continuation<? super Unit>, Object> {... public final Object invokeSuspend(Object $result) {MainActivity$init$1 mainActivity$init$1;Object coroutine_suspended = IntrinsicsKt.getCOROUTINE_SUSPENDED();int i = this.label;if (i == 0) {ResultKt.throwOnFailure($result);mainActivity$init$1 = this;LogUtil.e2$default("123", (String) null, 1, (Object) null);//對應打印日志的方法mainActivity$init$1.L$0 = mainActivity$init$1;mainActivity$init$1.label = 1;//在掛起點將自身這個匿名內部類包一層,創建的一個包裝協程體SafeContinuation it = new SafeContinuation(IntrinsicsKt.intercepted(mainActivity$init$1));//這里是對應post方法,這個MainActivity$init$1$1$1就是post方法傳入的lambda生成的匿名內部類對象HandlerPoolKt.post$default((String) null, new MainActivity$init$1$1$1(it), 1, (Object) null);Object orThrow = it.getOrThrow();if (orThrow == IntrinsicsKt.getCOROUTINE_SUSPENDED()) {DebugProbesKt.probeCoroutineSuspended(mainActivity$init$1);}if (orThrow == coroutine_suspended) {return coroutine_suspended;}} else if (i == 1) {mainActivity$init$1 = this;MainActivity$init$1 mainActivity$init$12 = (MainActivity$init$1) mainActivity$init$1.L$0;ResultKt.throwOnFailure($result);} else if (i == 2) {MainActivity$init$1 mainActivity$init$13 = (MainActivity$init$1) this.L$0;ResultKt.throwOnFailure($result);LogUtil.e2$default("456", (String) null, 1, (Object) null);return Unit.INSTANCE;} else {throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine");}LogUtil.e2$default("5", (String) null, 1, (Object) null);mainActivity$init$1.L$0 = mainActivity$init$1;mainActivity$init$1.label = 2;SafeContinuation safeContinuation = new SafeContinuation(IntrinsicsKt.intercepted(mainActivity$init$1));Continuation continuation = safeContinuation;Object orThrow2 = safeContinuation.getOrThrow();if (orThrow2 == IntrinsicsKt.getCOROUTINE_SUSPENDED()) {DebugProbesKt.probeCoroutineSuspended(mainActivity$init$1);}if (orThrow2 == coroutine_suspended) {return coroutine_suspended;}MainActivity$init$1 mainActivity$init$14 = mainActivity$init$1;LogUtil.e2$default("456", (String) null, 1, (Object) null);return Unit.INSTANCE;} }

    對應post方法傳入的匿名內部類:

    final class MainActivity$init$1$1$1 extends Lambda implements Function0<Unit> {final /* synthetic */ Continuation $it;/* JADX INFO: super call moved to the top of the method (can break code semantics) */MainActivity$init$1$1$1(Continuation continuation) {super(0);this.$it = continuation;}public final void invoke() {Continuation continuation = this.$it;Unit unit = Unit.INSTANCE;Result.Companion companion = Result.Companion;continuation.resumeWith(Result.m4constructorimpl(unit));} }
  • 在launch后,會經過一系列的協程內部調用,最后會走到MainActivity$init$1的invokeSuspend方法,第一次執行協程代碼塊時label會是0(label相當于走到了第幾步,是通過掛起點來分割步驟的)
  • 然后走到LogUtil.e2$default("123", (String) null, 1, (Object) null);去打印日志
  • 接著遇到掛起點,會執行SafeContinuation it = new SafeContinuation(IntrinsicsKt.intercepted(mainActivity$init$1));將自身這個匿名內部類包裝一層創建個新的協程體
  • 然后執行HandlerPoolKt.post$default((String) null, new MainActivity$init$1$1$1(it), 1, (Object) null);,其會創建一個匿名內部類(也就是post的lambda)來在下個時機恢復協程
  • 這時調用SafeContinuation的getOrThrow方法,會獲取到返回值,也就是IntrinsicsKt.getCOROUTINE_SUSPENDED(),表示當前協程會被掛起,然后return了invokeSuspend方法
  • 在某個時刻主線程相應了post事件,就會執行MainActivity$init$1$1$1對象的invoke方法,invoke方法就會調用匿名內部類的上層對象(jvm匿名內部類的特性是會隱式在構造中傳入上層對象)的resume方法來恢復協程
  • 這時協程會重新調用MainActivity$init$1的invokeSuspend方法,并且label變為了1,在label1里面會檢查是否有異常,沒有異常就會走到if else后面的代碼塊,打印日志"5"
  • 然后在創建一個新的SafeContinuation對象,然后在getOrThrow()會返回IntrinsicsKt.getCOROUTINE_SUSPENDED(),然后協程函數就停止執行了,因為后面沒有沒有了新的匿名內部類來引用MainActivity$init$1對象,所以其會在調用棧中層層出棧,然后引用鏈也會斷開,所以不會造成內存泄漏,只會造成協程一直掛起,后面的代碼塊得不到執行
  • 結論

    協程只掛起不恢復只會造成一直掛起,后面的代碼塊得不到執行

    上面的幾個步驟證明了該結論

    掛起的協程體存在匿名內部類中

    jvm的匿名內部類的特性之一是會在其隱式的構造函數中傳入上層對象,所以協程體的對象會被傳入到對應掛起點通過CPS轉換得來的匿名內部類對象中,而這個對象如果將來某個時段會調用resume,就會被某個代碼節點給引用著(可能是間接的main方法或線程run方法),相當于一層層匿名內部類串聯引用保存了協程體的對象

    協程只掛起不恢復不會造成協程泄漏

    通過上面的代碼發現,第二個掛起點處,也就是打印日志"5"的下方,代碼只調用了getOrThrow但沒有其他時機調用resume,也沒有將MainActivity$init$1對象傳到其他地方,而jvm內存回收是根據可達性分析算法決定對象可不可以被回收,此時invokeSuspend方法已經執行完畢,MainActivity$init$1對象也已不可達(沒有被其他對象引用),該協程就隨時有可能被gc給回收掉

    ?

    本篇文章只是代表個人觀察和分析所得,如有錯誤,歡迎大佬指出.

    end

    ?

    ?

    總結

    以上是生活随笔為你收集整理的分析Kotlin协程只挂起不恢复会怎样(是否存在协程泄漏),以及挂起的协程存在哪里?的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 秋霞在线视频观看 | 韩国黄色大片 | 蜜臀av在线播放 | 99热这里有| 天天操,夜夜操 | 亚洲图片欧美 | 中国性老太hd大全69 | 欧美福利在线观看 | 欧美日一区二区三区 | 在线观看的黄网 | 国产精品国产三级国产Av车上的 | aise爱色av | 人妻精品久久久久中文字幕 | 亚洲视频一二区 | 日本女人hd | 男女国产精品 | 久久激情综合 | 久久一区二区三区视频 | a级黄毛片 | 国产精品一区二区视频 | 老公吃小头头视频免费观看 | 成人a级网站| 日韩成人综合 | 三级理论电影 | 国产精品自慰网站 | 老女人一毛片 | 国产欧美精品久久久 | 色污网站| 一级国产特黄bbbbb | 啪视频在线观看 | 天堂久久一区 | 视频免费在线观看 | av老司机在线 | 18禁裸乳无遮挡啪啪无码免费 | 日韩人妻精品一区二区三区视频 | 欧美自拍视频在线观看 | 综合久草 | 在线观看免费高清在线观看 | 变态 另类 国产 亚洲 | 午夜免费大片 | 欧美伦理片网站 | 日韩欧美网站 | 99久久婷婷国产综合精品 | 日本wwwxx | 特级丰满少妇一级aaaa爱毛片 | 亚洲欧美日韩视频一区 | 免费观看日本 | 国产男女网站 | www.香蕉视频在线观看 | 777国产成人入口 | 亚洲人妻电影一区 | 亚洲精品久久久久久久久久久 | 久久综合中文 | av福利在线观看 | 成人免费播放视频 | 亚洲AV成人无码精品久久盆瓶 | 欧美性极品xxxx做受 | 亚洲春色另类 | 自拍毛片| 欧美另类人妖 | 九色一区 | 精品国产乱码久久久久久婷婷 | 操女人逼逼视频 | 成人欧美一区二区三区黑人冫 | 国产视频成人 | 免费搞黄网站 | 久在线观看视频 | 毛片国产精品 | sese欧美 | 日批视频免费观看 | 男男gay同性三级 | 日韩国产一级 | 久久在线中文字幕 | 四虎国产成人永久精品免费 | 欧美综合久久 | 欧美变态绿帽cuckold | 综合伊人久久 | 国产馆在线观看 | 69黄色片 | 色综合免费| 亚洲欧美日韩精品久久亚洲区 | 久草视频在线免费 | 国产精品嫩草av | 伊人成长网 | 大白屁股一区二区视频 | 精品无码一区二区三区的天堂 | 亚洲深夜视频 | 69超碰| 精品毛片在线观看 | 久草免费资源站 | 欧美一区二区高清 | 亚洲夜夜操 | 天天躁日日躁狠狠躁伊人 | 亚洲 小说区 图片区 都市 | 绿帽人妻精品一区二区 | 中国美女洗澡免费看网站 | 亚洲熟女一区二区三区 | 黄色专区| 国产又粗又大又爽 |