Share
Embed
マンガアプリのメモリ改善と解析方法
「DroidKaigi2022」の登壇資料です。
https://2022.droidkaigi.jp/
LINE Digital Frontier - TECH
October 12, 2022
Transcript
52 slides
-
• sai.choko • https://twitter.com/zhangho • 中国 -> ⽇本 -> 中国
-> ⽇本 • LINEマンガの開発 -
USER BASE ※2022年9⽉時点 MAU 作品数 取引額 作家数 WEBTOON Entertainment 最新実績
WEBTOON Entertainment が運営する代表的なサービスは 「LINEマンガ (⽇本)」「NAVER WEBTOON (韓国)」「WEBTOON (北南⽶・欧州)」「LINE WEBTOON (東南アジア)」など 8900 万 1000 億円 600 万⼈ 10 億 -
現在、将来 画⾯回転 Large Screen: Tablet, foldable Google Play Media Experience
Program (⼿数料30% -> 15%) -
LINEマンガで Out of memoryが全体crashの⽐率40% -> 5% OOMが40% 他 Crash 他
Crash 他 Crash 他 Crash 他 Crash 他 Crash 他 Crash 他 Crash 他 Crash 他 Crash 他 Crash 他 Crash 他 Crash OOM Crash OOM crash割合<5% 他 Crash 他 Crash 他 Crash 他 Crash 他 Crash 他 Crash 他 Crash 他 Crash 他 Crash 他 Crash 他 Crash OOM Crash こちらはあくまでイメージ図であります。 メモリ改善 -
解析⽅法 & tools • ログ • Java JVM基礎知識 • Android
studio メモリprofiler • Android メモリ監視メソッド • Bitmap画像のメモリ計算⽅法 -
12 Crashログ みなさん⼤好きなCrashログ: Crashログから検知 (Firebase Crashlytics、⾃社ログサービスなど) ログだけ頼ってメモリ問題を解決しようとしたが 根本的な解決には繋がらなかった。 いい点: 問題の箇所がすぐわかる
悪い点︓表⾯的な修正に終わる可能性がある、本質的な原因に辿り着かない -
• GC Object参照は⾊々絡んでいる。 • Depth: The shortest number of hops
from any GC root to the selected instance. GC treeとdepth -
Two important JVM tuning points in the java world •
Heap size • -Xms, -Xmx • android:largeHeap="true” • Garbage Collection(GC) • こちらはAndroid OSバージョンとともに進化 https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html - jvms-2.5 https://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html Java memory tuning -
• 特にAndroid 8.0でメモリ管理改善 • Compacting garbage collectorでfragment化したメモリをまとめる • Bitmapはjvm heapではなく、native
heapに保存される https://source.android.com/devices/tech/dalvik Android Runtime (ART) -
• Android 5,6,7で起こりやすい • RAM 2GB, 3GBで発⽣; 4GB以上は少ない • Android
8以上の端末ではOOMが少ない • ⽐較的にRAMが>=3GBのものが多いのでHeapサイズも⼤きい • Android 8以上ではNative heapにbitmapを保存 • Android 8ではConcurrent compacting garbage collectorなど メモリ回収処理が最適化されている LINEマンガ OOMの発⽣のデバイス統計 -
• どんなタイミングでOOM するかを可視化したい • totalFreeMemory が0だ とOOMが発⽣する • 要はVMのmax Memoryを
超えるとメモリが⾜りな いのでOOM https://stackoverflow.com/a/18375641 MemoryUtil -
totalFreeMemoryで 残りのメモリを数値化したい private const val MEGA_BYTE = 1048576 // 1024
* 1024 @JvmStatic fun printCurrentApplicationVMMemory() { val runtimeVersion = System.getProperty("java.vm.version") val runtime = Runtime.getRuntime() val maxMemory = runtime.maxMemory() / MEGA_BYTE val freeMemory = runtime.freeMemory() / MEGA_BYTE val totalMemory = runtime.totalMemory() / MEGA_BYTE val totalFreeMemory = maxMemory - totalMemory + freeMemory Timber.d( "#Memory CurrentApplicationVMMemory(MB) %s, %s, %s, %s, %s", " totalFreeMemory: $totalFreeMemory", " runtimeVersion: $runtimeVersion", " maxMemory: $maxMemory", " freeMemory: $freeMemory", " totalMemory: $totalMemory", ) } MemoryUtil -
33 🤔2048 x 1536のjpeg画像のファイルサイズが1MBぐらいなのにAndroid bitmapサイズは12MB になる。なぜ︖ • Bimap画像サイズ(memory) > Jpeg/PNG/webP(圧縮アルゴリズム)ファイルサイズ(dis
k) Bitmap画像: ARGB_8888⽅式 (LINEマンガでは画像のクオリティを維持するためRGB_565を採 ⽤しない) で保存する場合のBitmapメモリサイズ(標準保存⽅式) Each pixel is stored on 4 bytes Bitmap image memory size = height x width x 4byte 例: 2048 x 1536 => 2048 x 1536 x 4 = 12582912bytes ≒ 12MB 1024 x 1600 => 1024 x 1600 x 4 = 65536000bytes ≒ 6.8MB 512 x 384 => 512 x 384 x 4 = 786432bytes ≒ 0.75MB • OutOfMemory: Faild to allocate 12582912bytes…の場合は驚かないでください。12MB/4=3MBより ⼩さいファイルサイズ(普段は1MBぐらい)の画像かもしれません。 • 質問: 最新のWebPフォーマットの画像だったらBitmapメモリサイズが⼩さくなる︖ Bitmap画像のメモリサイズ計算⽅法 -
• Picasso .resize(600, 200) • Glideのは基本的にImageViewのサイズを⾃動判別できるが必要に応じ て.override(targetWidth, targetHeight)、 CustomTarget<Drawable>(targetImageWidth, targetImageHeight)でサ
イズを設定 画像ライブラリー使う場合: オリジナル画像をロードしない ImageView ImageView サーバーから必要以上に⼤きい画像が送られる場合がありませんか? ImageView サイズ取得 -
• Bitmapを直接弄る時にメモリにロードする時のサイズを調整: • 画像のロードサイズを画⾯サイズに合わせる • option.inSampleSize = 2 // 2の倍数
• https://developer.android.com/topic/performance/graphics/load -bitmap 画像サイズ⼿動調整: inSampleSize -
画像分割ロード 問題 • 縦⻑い画像のままだと⼆つの問題が発⽣する • GL_MAX_TEXTURE_SIZEとかCanvas: trying to draw too
large で古い端末では描画できない可能性がある • RecyclerViewで画⾯に表⽰されていない部分がrecyclerできない 解決⽅法 • meta dataを参考に事前に分割する適切なサイズを計算する • Android 8.0以下: BitmapRegionDecoderで分割読み込み 、 読み込みスピードを犠牲 • Android 8.0以上: オリジナルBitmap読み込んでからsub bitmapに分割して表⽰、 読み込みスピード優先 -
• fast scrollで画⾯上に表⽰する必要のない 画像はロードのcallbackが来たら処理しない • NO_POSITIONのholderの画像はもうロードする必要がない。 public void onBitmapLoaded(Bitmap bitmap,
… int requestPosition) { …. int adapterPosition = holder. getAbsoluteAdapterPosition(); // check whether it is valid position. // - avoid calling unnecessary logic such as createBitmap. // - this also fix when fast scroll wrong position bitmap set. if (adapterPosition == RecyclerView.NO_POSITION || requestPosition != adapterPosition) { return; } …. Create bitmap … Viewer: RecyclerViewのfast scroll対応 NO_POSITION … … NO_POSITION -
• Memcacheがずっとメモリを占⽤しているのを防ぎましょう。 • Picasso⼿動でclearする必要あります。しないとmemcacheで15%のheapメ モリが使えなくなります => Picasso.cache.clear() • Glideなどはactivity/viewなどのcontextにより⾃動メモリ解放しているらしい が必要に応じてclearしておく
=> Glide.get(context).clearMemory() Memcache: Strong referenceが必要ないときにclearする -
private var binding: xxxxBinding? = null …. override fun onDestroyView()
{ super.onDestroyView() binding = null } 参照: Release Binding/Adapter -
• Adapter release when onDestroy • or not use field
adapter, just cast for use adapter = null or recyclerView.setAdapter(null); (adapter as xxxxAdapter).get….. 参照: Release Adapter -
class xxxxFragment { private val myView: View? = null //
Bad practice private val myDialogFragment MyDialogFragment? = null // Bad practice } • Filedに保持しない、必要な時はbinding/findFragmentByTag/byId で参照できる 参照: view/dialogを保持しない -
• Handler(Looper.getMainLooper()).postDelayed(…..). // Bad practice • 実際画像バナー⾃動横scrollでこれを使って無限ループで⾃⼰参照しているところがあ りました。バナー画像は⼤きいですからメモリリークされてメモリにずっと残っていま した。 •
rootView.postDelayed(…..) // Good practice • Runnableのstop処理を⾃前で書いてもいいですがこの場合viewのpost/postDelayed が適切 • Viewに紐ついてPostDelayedするとattatch状態もちゃんとチェックしてくれます。 View.java 参照: 遅延処理はViewのpostDelayedを使う -
• Flyweight or factory method で⼤きいobjectを使い回す • https://refactoring.guru/design-patterns/flyweight • Singletonもしくはfactory
methodでobjectを⼀元管理 おまけ: デザインパターン -
• Google I/O 2022でもLarge screen(tablet/foldable)が話題 • Large screen対応アプリはGoogle playの該当デバイス種類検索ラン キング上位に現れるなど優遇される
• Play Media Experience Programに申請して対応すると⼿数料 が30% -> 15%になります。 • ConfigutationChange/rotationなどで発⽣する可能性が⾼いメモリ リークなど問題ないか解析が必要になっています • LINEマンガは既にLarge Screen対応済み おまけ: Google large screen対応