TransactionTooLargeException原因分析

來源:互聯網
上載者:User

標籤:timestamp   源碼   zygote   百度   message   cep   isp   規模   util   

前兩天測試提了一個crash的bug,崩潰棧如下:

Device Manufacturer : Meizu
Device Model        : M5 Note
Android Version     : 7.0
Android SDK         : 24
App VersionName     : 1.1.2
App VersionCode     : 16
App Max Mem         : 512MB
UUID                : 864105030589222
Timestamp           : 10-16 14:27:22.880
CurrentThread       : main#1
TotalMem\AvailMem   : 3796MB\1037MB
Crash Detail        : 

java.lang.RuntimeException: android.os.TransactionTooLargeException: data parcel size 531500 bytes
at android.app.ActivityThread$StopInfo.run(ActivityThread.java:4112)
at android.os.Handler.handleCallback(Handler.java:836)
at android.os.Handler.dispatchMessage(Handler.java:103)
at android.os.Looper.loop(Looper.java:203)
at android.app.ActivityThread.main(ActivityThread.java:6519)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1113)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:974)
Caused by: android.os.TransactionTooLargeException: data parcel size 531500 bytes
at android.os.BinderProxy.transactNative(Native Method)
at android.os.BinderProxy.transact(Binder.java:627)
at android.app.ActivityManagerProxy.activityStopped(ActivityManagerNative.java:3990)
at android.app.ActivityThread$StopInfo.run(ActivityThread.java:4104)
... 7 more

雖說一眼就看出是binder通訊引發的崩潰,但就如同OOM問題,定性問題容易,但定位問題卻不容易。

 

下面開始問題分析:

1) 分析拋出的原因或條件,查看源碼android_util_binder.cpp,查看系統層在什麼情況下會拋出TransactionTooLargeException,中可知

   在binder驅動處理失敗後,如果傳輸的parcel體積超過200kb,則會拋出TransactionTooLargeException,因此引發該問題的原因是binder調用

   傳輸的資料太大導致,問題分析重點應側重binder資料轉送。

 

 2) 分析崩潰棧,找出引發該問題的binder調用是ActivityManagerProxy.activityStopped,從中大概推知問題的發生時機在Activity stopped的時候。

 3) 網上百度相關的解決方案,關鍵詞是TransactionTooLargeException activityStopped,現象類似的問題、原因、解決方案如下:

  • 問題原因:FragmentStatePagerAdapter的實現有缺陷,因為其預設實現會持續儲存曆史Fragment執行個體的狀態資料曆史,在逐漸地積累、儲存資料後,最終導致發送的資料包體積超過限制200KB 。

       

 

      參見:https://stackoverflow.com/questions/11451393/what-to-do-on-transactiontoolargeexception

 

  • 解決方案:重寫FragmentStatePagerAdapter的saveState方法,使其不儲存曆史Fragment執行個體的狀態資料。

       

 

 4) 工程中崩潰點也恰巧使用了FragmentStatePagerAdapter,現象也類似,然後立即應用該方案,但沒有效果。

 5)繼續分析該問題,深入代碼進行白盒分析,根據日誌輸出和代碼結構,最後定位問題原因構建Fragment執行個體時傳遞ArrayList給Fragment的建構函式,

     在Fragment的建構函式內部將該ArrayList作為Parcelable存放在Bundle,以供該Fragment初始化時從bundle中讀取, 在資料量比較大時,就會拋出TransactionTooLargeException

 6) 解決方案:構建Fragment執行個體時傳遞ArrayList給Fragment的建構函式,在Fragment被載入時無需從Bundle中讀取,這樣可避免TransactionTooLargeException,又提高程式執行效率。

 7) 總結

     TransactionTooLargeException經常出現在binder通訊的情境中,導致其出現的直接原因是binder通訊的資料包過大,而根本原因是使用者的理解和設計軟體問題,因為binder通訊的設計初衷是

跨進程的小規模資料體量的通訊,從其記憶體設定就可看出:binder空間最大是1MB,而且是被所有進程共用。如果不理解binder的設計和適用情境,錯誤地將binder用於大資料量傳輸,那就會出現問題。

 

TransactionTooLargeException原因分析

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.