Berbagi teknologi

Pengoptimalan memori pengoptimalan kinerja Android

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

Pengoptimalan memori pengoptimalan kinerja Android

masalah memori

  • meronta-ronta ingatan
  • kebocoran memori
  • memori meluap

meronta-ronta ingatan

Memory thrashing mengacu pada pembuatan dan penghancuran sejumlah besar objek dalam waktu singkat, yang mengakibatkan seringnya dilakukan aktivitas pengumpulan sampah (Garbage Collection, GC). Aktivitas GC yang sering dilakukan ini menghabiskan banyak sumber daya CPU dan dapat menyebabkan kelambatan aplikasi atau penurunan kinerja.

Performa: Kurva memori tidak rata.

kebocoran memori

Kebocoran memori terjadi ketika aplikasi menyimpan referensi ke objek yang tidak diperlukan lagi, menyebabkan objek tersebut gagal diambil kembali oleh pengumpul sampah, sehingga menempati ruang memori yang sebenarnya bisa dikosongkan. Seiring waktu, kebocoran memori mengakibatkan semakin sedikitnya memori yang tersedia, yang pada akhirnya dapat menyebabkan aplikasi mogok atau penurunan kinerja.

memori meluap

Memory overflow terjadi ketika aplikasi mencoba mengalokasikan lebih banyak ruang memori, namun sistem tidak dapat memenuhi permintaan tersebut karena tidak ada lagi ruang memori yang cukup untuk dialokasikan. Hal ini biasanya menyebabkan aplikasi mengeluarkan pengecualian OutOfMemoryError.

Alat Deteksi

  • Profiler Memori
  • Penganalisis Memori
  • KebocoranCanary

Profiler Memori

  • Memory Profiler adalah alat analisis memori yang disertakan dengan Android Studio.
  • Grafik real-time menunjukkan penggunaan memori program.
  • Identifikasi kebocoran memori, perontokan, dan banyak lagi.
  • Memberikan kemampuan untuk menangkap heap dump, memaksa GC, dan melacak alokasi memori.

Penganalisis Memori

  • Alat analisis Java Heap yang canggih untuk menemukan kebocoran memori dan penggunaan memori.
  • Hasilkan laporan keseluruhan, analisis masalah, dan banyak lagi.

KebocoranCanary

  • Deteksi kebocoran memori otomatis.
    • LeakCanary secara otomatis mendeteksi kebocoran pada objek berikut: Aktivitas, Fragmen, Tampilan, ViewModel, Layanan.
  • Situs web resmi: https://github.com/square/leakcanary

Mekanisme manajemen memori

Jawa

Struktur memori Java: tumpukan, tumpukan mesin virtual, area metode, penghitung program, tumpukan metode lokal.

Algoritma daur ulang memori Java:

  • Algoritma tandai dan sapu:
    1. Tandai benda-benda yang perlu didaur ulang
    2. Daur ulang semua objek yang ditandai secara seragam.
  • Algoritma penyalinan:
    1. Bagilah memori menjadi dua bagian yang berukuran sama.
    2. Setelah satu blok memori habis, objek yang masih ada akan disalin ke blok lain.
  • Algoritma penandaan-pengumpulan:
    1. Proses penandaannya sama dengan algoritma “mark-and-sweep”.
    2. Objek bertahan hidup berpindah ke satu ujung.
    3. Hapus sisa memori.
  • Algoritma pengumpulan generasi:
    • Gabungkan keunggulan beberapa algoritma pengumpulan.
    • Tingkat kelangsungan hidup objek generasi baru rendah dan algoritma penyalinan digunakan.
    • Tingkat kelangsungan hidup objek pada generasi lama tinggi dan algoritma pengurutan tanda digunakan.

Kekurangan dari algoritma mark-clear: Penandaan dan pembersihan tidak efisien dan akan menghasilkan sejumlah besar fragmen memori yang terputus-putus.

Algoritma replikasi: mudah diterapkan dan efisien untuk dijalankan. Kekurangan: Membuang separuh ruang.

Algoritme mark-compact: menghindari fragmentasi memori yang disebabkan oleh mark-clean dan menghindari pemborosan ruang pada algoritma penyalinan.

Bahasa Indonesia: Bahasa Indonesia: Android

Alokasi elastis memori Android, nilai alokasi, dan nilai maksimum dipengaruhi oleh perangkat tertentu.

Algoritma daur ulang Dalvik dan algoritma daur ulang ART keduanya merupakan mekanisme pengumpulan sampah yang digunakan untuk manajemen memori di sistem operasi Android.

Algoritma daur ulang Dalvik:

  • Algoritma tandai dan sapu.
  • Keuntungannya adalah implementasinya mudah. Kerugiannya adalah eksekusi aplikasi akan terhenti selama fase penandaan dan pembersihan, yang akan menyebabkan aplikasi terhenti sementara dan memengaruhi pengalaman pengguna.

Algoritma daur ulang seni:

  • Algoritma Pemadatan Pengumpulan Sampah. Perbaikan telah dilakukan berdasarkan algoritma mark-sweep untuk mengurangi waktu jeda selama pengumpulan sampah.
  • Penandaan Bersamaan: ART memperkenalkan fase penandaan bersamaan, yang berarti dapat terjadi bersamaan dengan pelaksanaan aplikasi. Hal ini mengurangi waktu jeda karena pengumpulan sampah.
  • Pembersihan dan pemadatan: Selama fase pembersihan, ART tidak hanya membersihkan objek yang tidak ditandai, namun juga memadatkan memori, yang berarti memindahkan objek yang masih hidup bersama-sama untuk mengurangi fragmentasi memori. Hal ini membuat manajemen memori lebih efisien dan mengurangi kemungkinan kegagalan alokasi memori.
  • Pengumpulan adaptif: ART juga memperkenalkan konsep pengumpulan adaptif, yang berarti secara otomatis menyesuaikan frekuensi dan cara pengumpulan sampah berdasarkan perilaku aplikasi dan pola penggunaan memori. Hal ini memungkinkan ART untuk lebih beradaptasi dengan kebutuhan aplikasi yang berbeda.

Mekanisme LMK:

  • Mekanisme Pembunuh Memori Rendah.
  • Fungsi utamanya adalah untuk mengakhiri beberapa proses latar belakang sesuai dengan kebijakan prioritas tertentu ketika memori sistem tidak cukup untuk melepaskan memori dan memastikan stabilitas dan daya tanggap sistem.

menyelesaikan

Masalah kehilangan memori

Kode masalah simulasi
public class ShakeActivity extends AppCompatActivity {

    private static Handler mHandler = new Handler() {
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            String str = "";
            for (int i = 0; i < 10000000; i++) {
                str += i;
            }
            mHandler.sendEmptyMessageDelayed(1, 30);
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_shake);
    }

    public void startClick(View view) {
        mHandler.sendEmptyMessage(1);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mHandler.removeCallbacksAndMessages(null);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
Gunakan alat Memory Profiler untuk mendeteksi

Memory Profiler dapat melihat alokasi memori, klik "Rekam alokasi Java/Kotlin".

Masukkan deskripsi gambar di sini

Arti di atas:

  • Java: Memori yang dialokasikan oleh kode Java atau Kotlin.
  • Asli: Memori yang dialokasikan oleh kode C atau C++.
  • Grafik: Memori yang digunakan oleh antrian buffer grafis untuk menampilkan piksel ke layar (termasuk permukaan GL, tekstur GL, dll.). Memori bersama CPU.
  • Stack: Memori yang digunakan oleh tumpukan asli dan tumpukan Java dalam aplikasi. Hal ini biasanya berkaitan dengan berapa banyak thread yang dijalankan aplikasi Anda.
  • Memori yang digunakan oleh aplikasi untuk memproses kode dan sumber daya seperti dex bytecode, kode dex yang dioptimalkan atau dikompilasi, pustaka .so, dan font.
  • Aplikasi ini menggunakan memori yang sistemnya tidak yakin bagaimana cara mengklasifikasikannya.
  • Jumlah objek Java/Kotlin yang dialokasikan oleh aplikasi. Jumlah ini tidak memperhitungkan objek yang dialokasikan dalam C atau C++.

Arti berikut:

  • Alokasi: Lulus malloc() ataunew Jumlah objek yang dialokasikan oleh operator.
  • Deallokasi: melalui free() ataudelete Jumlah objek yang dibatalkan alokasinya oleh operator.
  • Ukuran Alokasi: Ukuran total semua alokasi selama periode waktu yang dipilih, dalam byte.
  • Ukuran Deallokasi: Ukuran total memori yang dilepaskan selama periode waktu yang dipilih, dalam byte.
  • Jumlah Total: Alokasi dikurangi Deallokasi.
  • Ukuran Tersisa: Ukuran Alokasi dikurangi Ukuran Deallokasi.
  • Ukuran Dangkal: Ukuran total semua instance di heap, dalam byte.

Analisis gambar di atas:

Masukkan deskripsi gambar di sini

Nilai Alokasi dan Deallokasi pada area ini relatif sama, dan Ukuran Dangkalnya relatif besar, menunjukkan bahwa objek mungkin sering dibuat dan dimusnahkan.

Masukkan deskripsi gambar di sini

Setelah mengklik, Anda dapat melihat informasi tumpukan panggilan, dan dikombinasikan dengan kode, Anda dapat menyimpulkan bahwa ada masalah jitter memori di Handler.

Kiat pengoptimalan
  • Hindari membuat dan menghancurkan objek secara sering.

Masalah kebocoran memori

Kode masalah simulasi
public class CallbackManager {
    public static ArrayList<Callback> sCallbacks = new ArrayList<>();

    public static void addCallback(Callback callback) {
        sCallbacks.add(callback);
    }

    public static void removeCallback(Callback callback) {
        sCallbacks.remove(callback);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
public class LeakActivity extends AppCompatActivity implements Callback {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_leak);
        ImageView imageView = findViewById(R.id.imageView);
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.splash);
        imageView.setImageBitmap(bitmap);
        CallbackManager.addCallback(this);
    }

    @Override
    public void onOperate() {

    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
Gunakan alat LeakCanary untuk mendeteksi

Tambahkan perpustakaan dependen:

debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.14'
  • 1

Setelah terjadi kebocoran memori, LeakCanary akan menghasilkan informasi yang relevan dan secara otomatis membuangnya:

Masukkan deskripsi gambar di sini

Seperti yang terlihat dari gambar di atas: LeakActivity mengalami kebocoran memori, dan hubungan rantai referensi ditampilkan.

Tentu saja, Anda juga dapat membuat file hprof dan melihat informasi spesifik melalui alat Profiler:

Masukkan deskripsi gambar di sini

Seperti terlihat dari gambar di atas: 10 titik kebocoran telah terjadi, termasuk LeakActivity. Klik pada LeakActivity untuk melihat objek memori yang bocor dan memeriksa rantai referensi.

Kiat pengoptimalan
  • Daur ulang elemen koleksi tepat waktu.
  • Hindari referensi statis ke terlalu banyak contoh.
  • Gunakan kelas dalam statis.
  • Tutup objek sumber daya dengan segera.

Optimasi bitmap

Jika Anda tidak melepaskan sumber daya gambar setelah menggunakan Bitmap, hal ini mudah terjadiKebocoran memori, mengakibatkan memori meluap

Model memori bitmap
  • Sebelum api10 (Android 2.3.3): Objek bitmap ditempatkan di memori heap, dan data piksel ditempatkan di memori lokal.
  • Setelah api10: semua ada di memori heap.
  • Setelah api26 (Android8.0): data piksel ditempatkan di memori lokal. Hal ini memungkinkan data piksel Bitmap pada lapisan asli dirilis dengan cepat bersama dengan objek lapisan Java.

Daur ulang memori:

  • Sebelum Android 3.0, Anda perlu memanggilnya secara manualBitmap.recycle()Lakukan daur ulang Bitmap.
  • Mulai Android 3.0, sistem menyediakan manajemen memori yang lebih cerdas, dan dalam banyak kasus, tidak perlu mendaur ulang Bitmap secara manual.

Konfigurasi piksel bitmap:

KonfigurasiUkuran byte yang ditempati (byte)menjelaskan
ALFA_81saluran transparan tunggal
RGB_5652Warna RGB sederhana
ARGB_88884Warna asli 24-bit
RGBA_F168Android 8.0 Baru (HDR)

Hitung memori yang ditempati oleh Btimap:

  • Peta bit#getByteCount()
  • getWidth() * getHeight() * 1 piksel memakan memori
Direktori file sumber daya

Masalah file sumber daya:

  • mdpi (kepadatan sedang): sekitar 160dpi, 1x sumber daya.
  • hdpi (kepadatan tinggi): sekitar 240dpi, sumber daya 1,5x.
  • xhdpi (Kepadatan Ekstra Tinggi): Sekitar 320dpi, sumber daya 2x.
  • xxhdpi (Kepadatan Ekstra Ultra Tinggi): Sekitar 480dpi, sumber daya 3x.
  • xxxhdpi (Kepadatan Ekstra Ultra Tinggi): Sekitar 640dpi, sumber daya 4x.

Kode tes:

private void printBitmap(Bitmap bitmap, String drawable) {
    String builder = drawable +
            " Bitmap占用内存:" +
            bitmap.getByteCount() +
            " width:" +
            bitmap.getWidth() +
            " height:" +
            bitmap.getHeight() +
            " 1像素占用大小:" +
            getByteBy1px(bitmap.getConfig());
    Log.e("TAG", builder);
}

private int getByteBy1px(Bitmap.Config config) {
    if (Bitmap.Config.ALPHA_8.equals(config)) {
        return 1;
    } else if (Bitmap.Config.RGB_565.equals(config)) {
        return 2;
    } else if (Bitmap.Config.ARGB_8888.equals(config)) {
        return 4;
    }
    return 1;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
// 逻辑密度
float density = metrics.density;
// 物理密度
int densityDpi = metrics.densityDpi;
Log.e("TAG", density + "-" + densityDpi);

// 1倍图
Bitmap bitmap1 = BitmapFactory.decodeResource(getResources(), R.drawable.splash1);
printBitmap(bitmap1, "drawable-mdpi");

// 2倍图
Bitmap bitmap2 = BitmapFactory.decodeResource(getResources(), R.drawable.splash2);
printBitmap(bitmap2, "drawable-xhdpi");

// 3倍图
Bitmap bitmap3 = BitmapFactory.decodeResource(getResources(), R.drawable.splash3);
printBitmap(bitmap3, "drawable-xxhdpi");

// 4倍图
Bitmap bitmap4 = BitmapFactory.decodeResource(getResources(), R.drawable.splash4);
printBitmap(bitmap4, "drawable-xxxhdpi");

// drawable
Bitmap bitmap5 = BitmapFactory.decodeResource(getResources(), R.drawable.splash);
printBitmap(bitmap5, "drawable");
/*
        3.0-480
        drawable-mdpi Bitmap占用内存:37127376 width:2574 height:3606 1像素占用大小:4
        drawable-xhdpi Bitmap占用内存:9281844 width:1287 height:1803 1像素占用大小:4
        drawable-xxhdpi Bitmap占用内存:4125264 width:858 height:1202 1像素占用大小:4
        drawable-xxxhdpi Bitmap占用内存:2323552 width:644 height:902 1像素占用大小:4
        drawable Bitmap占用内存:37127376 width:2574 height:3606 1像素占用大小:4
         */
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

menjelaskan:

1dp pada perangkat mdpi1px, 1dp pada perangkat xhdpi2px, 1dp==3px pada perangkat xxhdpi.

Oleh karena itu, perangkat saat ini adalah xxhdpi, jadi lebar gambar yang sama di bawah sumber daya xxhdpi adalah 858, di bawah sumber daya mdpi akan diperbesar 3 kali dan lebarnya 2574, dan di bawah sumber daya xhdpi akan diperbesar 1,5 kali dan lebarnya 1287.

Kiat pengoptimalan
  • Siapkan beberapa kumpulan sumber daya gambar.
  • Pilih metode decoding yang sesuai.
  • Siapkan cache gambar.

Pengunduhan kode sumber