日韩性视频-久久久蜜桃-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 | 免费簧片在线观看 | 捆绑japanhdxxxxvideos | 久久精品亚洲天堂 | 国产人妻777人伦精品hd | 亚洲区国产区 | 一级一级黄色片 | 亚洲一卡二卡在线观看 | 神马久久影院 | 99在线成人精品视频 | 欧美人体做爰大胆视频 | 久久久久女教师免费一区 | 日本精品一二三区 | 撕开少妇裙子猛然进入 | 国产精品亚洲综合 | 德国艳星videos极品hd | 日本高清免费aaaaa大片视频 | 成人免费性生活视频 | 黄页视频在线观看 | 借种(出轨高h) | 最近最新最好看的2019 | 中国黄色在线视频 | xxx一区| 成人字幕 | 成人短视频在线 | 欧美一级在线观看视频 | a级黄色在线观看 | 手机免费av | 亚洲妇女体内精汇编 | 亚洲成av人片一区二区梦乃 | 成人av福利| 一区二区三区观看 | 午夜影院男女 | 久久片 | www.热久久| 青青青青青青青青草 | 亚洲高清视频一区二区 | 日韩毛片一区二区三区 | 久久加勒比 | av黄色网址 | 午夜天堂 | 欧美在线一级 | 杨幂一区二区三区免费看视频 | 浓精喷进老师黑色丝袜在线观看 | 蜜桃av噜噜一区二区三区小说 | 欧美 日韩 高清 | 亚洲国产精品美女 | 午夜精品久久久久久久91蜜桃 | 国内久久精品 | av男人的天堂av| 黄色一级视频片 | jizz日本在线观看 | 中国女人一级一次看片 | 久久爱一区二区 | 亚洲a影院| 久久发布国产伦子伦精品 | 蓝牛av| 欧美高跟鞋交xxxxxhd | 日本高清免费aaaaa大片视频 | 久久成人福利 | 欧美日韩在线中文字幕 | 草草视频在线播放 | 国产免费无遮挡 | 亚洲国产精品毛片av不卡在线 | 亚洲视频色| 色小姐av | 国产成人免费 | 性欧美jzjz2 九草影院 | 国产无遮挡呻吟娇喘视频 | 北条麻妃一区二区三区免费 | 日韩中文字幕国产 | 成人免费在线播放视频 | 蜜臀久久99静品久久久久久 | 亚洲一区二区三区在线视频 | 亚洲精品一区二区三区精华液 | 九九九久久久 | 爱视频福利网 | 制服下的诱惑暮生 | 欧美成人黑人xx视频免费观看 | 伊人88 | 日本中文字幕免费 | 日本黄色片在线播放 | 一本色道久久综合亚洲精品酒店 | 天天干干天天 | 性a视频 | 成人免费区一区二区三区 | 精品久久久久久亚洲精品 | 精品一区二三区 | 日本在线网站 | 日韩免费观看一区二区三区 | 福利视频精品 | 又色又爽又黄gif动态图 | 人妻互换一二三区激情视频 | 国产精品视频成人 | 黄色免费一级 | 免费无码毛片一区二三区 | 国产精品性| 欧美精品极品 |