Pertanyaan Bagaimana cara menemukan penggunaan memori aplikasi saya di Android?


Bagaimana saya dapat menemukan memori yang digunakan pada aplikasi Android saya, secara terprogram?

Saya harap ada cara untuk melakukannya. Plus, bagaimana cara mendapatkan memori telepon gratis juga?


745
2018-02-19 17:12


asal


Jawaban:


Perhatikan bahwa penggunaan memori pada sistem operasi modern seperti Linux adalah sebuah sangat rumit dan sulit dimengerti. Bahkan kemungkinan Anda benar-benar menafsirkan angka apa pun yang Anda peroleh sangat rendah. (Cukup banyak setiap kali saya melihat jumlah penggunaan memori dengan insinyur lain, selalu ada diskusi panjang tentang apa yang sebenarnya mereka maksudkan sehingga hanya menghasilkan kesimpulan yang samar-samar.)

Catatan: kami sekarang memiliki dokumentasi yang jauh lebih luas Mengelola Memori Aplikasi Anda yang mencakup banyak materi di sini dan lebih terkini dengan keadaan Android.

Hal pertama adalah mungkin membaca bagian terakhir dari artikel ini yang memiliki beberapa diskusi tentang bagaimana memori dikelola di Android:

Perubahan API layanan dimulai dengan Android 2.0

Sekarang ActivityManager.getMemoryInfo() adalah API level tertinggi kami untuk melihat penggunaan memori secara keseluruhan. Ini sebagian besar ada untuk membantu pengukur aplikasi seberapa dekat sistem yang akan datang untuk tidak memiliki lebih banyak memori untuk proses latar belakang, sehingga perlu mulai membunuh proses yang diperlukan seperti layanan. Untuk aplikasi Java murni, ini harus sedikit digunakan, karena batas tumpukan Java ada sebagian untuk menghindari satu aplikasi dari mampu menekankan sistem ke titik ini.

Pergi ke tingkat yang lebih rendah, Anda dapat menggunakan API Debug untuk mendapatkan informasi tingkat kernel mentah tentang penggunaan memori: android.os.Debug.MemoryInfo

Catatan dimulai dengan 2.0 ada juga API, ActivityManager.getProcessMemoryInfo, untuk mendapatkan informasi ini tentang proses lain: ActivityManager.getProcessMemoryInfo (int [])

Ini mengembalikan struktur MemoryInfo tingkat rendah dengan semua data ini:

    /** The proportional set size for dalvik. */
    public int dalvikPss;
    /** The private dirty pages used by dalvik. */
    public int dalvikPrivateDirty;
    /** The shared dirty pages used by dalvik. */
    public int dalvikSharedDirty;

    /** The proportional set size for the native heap. */
    public int nativePss;
    /** The private dirty pages used by the native heap. */
    public int nativePrivateDirty;
    /** The shared dirty pages used by the native heap. */
    public int nativeSharedDirty;

    /** The proportional set size for everything else. */
    public int otherPss;
    /** The private dirty pages used by everything else. */
    public int otherPrivateDirty;
    /** The shared dirty pages used by everything else. */
    public int otherSharedDirty;

Tetapi untuk apa perbedaannya adalah antara Pss, PrivateDirty, dan SharedDirty... nah sekarang kesenangannya dimulai.

Banyak memori di Android (dan sistem Linux pada umumnya) sebenarnya dibagi di beberapa proses. Jadi berapa banyak memori yang digunakan proses tidak benar-benar jelas. Tambahkan di atas itu paging ke disk (apalagi swap yang tidak kita gunakan di Android) dan itu bahkan kurang jelas.

Jadi jika Anda mengambil semua RAM fisik yang benar-benar dipetakan ke setiap proses, dan menambahkan semua proses, Anda mungkin akan berakhir dengan angka yang jauh lebih besar daripada total RAM sebenarnya.

Itu Pss angka adalah metrik yang dihitung kernel yang memperhitungkan pembagian memori akun - pada dasarnya setiap halaman RAM dalam suatu proses diskalakan oleh rasio jumlah proses lain yang juga menggunakan halaman itu. Dengan cara ini Anda dapat (secara teori) menambahkan pss di semua proses untuk melihat RAM total yang mereka gunakan, dan membandingkan pss antara proses untuk mendapatkan gambaran kasar tentang bobot relatif mereka.

Metrik menarik lainnya di sini adalah PrivateDirty, yang pada dasarnya adalah jumlah RAM di dalam proses yang tidak dapat di-paged ke disk (tidak didukung oleh data yang sama pada disk), dan tidak dibagi dengan proses lainnya. Cara lain untuk melihat ini adalah RAM yang akan tersedia untuk sistem ketika proses itu hilang (dan mungkin dengan cepat dimasukkan ke dalam cache dan penggunaan lain dari itu).

Itu cukup banyak SDK API untuk ini. Namun ada lebih banyak yang bisa Anda lakukan sebagai pengembang dengan perangkat Anda.

Menggunakan adb, ada banyak informasi yang bisa Anda dapatkan tentang penggunaan memori dari sistem yang sedang berjalan. Yang umum adalah perintahnya adb shell dumpsys meminfo yang akan memuntahkan banyak informasi tentang penggunaan memori dari setiap proses Java, yang berisi info di atas serta berbagai hal lainnya. Anda juga bisa menggunakan nama atau pid dari satu proses untuk melihat, misalnya adb shell dumpsys meminfo system beri saya proses sistem:

** MEMINFO di pid 890 [sistem] **
                    pribumi dalvik total lainnya
            ukuran: 10940 7047 N / A 17987
       dialokasikan: 8943 5516 N / A 14459
            bebas: 336 1531 T / A 1867
           (Pss): 4585 9282 11916 25783
  (berbagi kotor): 2184 3596 916 6696
    (priv kotor): 4504 5956 7456 17916

 Objek
           Dilihat: 149 ViewRoots: 4
     AppContexts: 13 Aktivitas: 0
          Aset: 4 AssetManagers: 4
   Pengikat Lokal: 141 Proxy Binders: 158
Penerima Maut: 49
 Soket OpenSSL: 0

 SQL
            heap: 205 dbFiles: 0
       numPagers: 0 tidak aktifPageKB: 0
    activePageKB: 0

Bagian atas adalah yang utama, di mana size adalah ukuran total dalam ruang alamat dari tumpukan tertentu, allocated adalah kb alokasi aktual yang dipikirkan oleh tumpukan itu, free adalah sisa kb bebas yang dimiliki heap untuk alokasi tambahan, dan pss dan priv dirty sama seperti yang dibahas sebelumnya khusus untuk halaman yang terkait dengan masing-masing tumpukan.

Jika Anda hanya ingin melihat penggunaan memori di semua proses, Anda dapat menggunakan perintah adb shell procrank. Output ini pada sistem yang sama terlihat seperti:

  PID Vss Rss Pss Uss cmdline
  890 84456K 48668K 25850K 21284K system_server
 1231 50748K 39088K 17587K 13792K com.android.launcher2
  947 34488K 28528K 10834K 9308K com.android.wallpaper
  987 26964K 26956K 8751K 7308K com.google.process.gapps
  954 24300K ​​24296K 6249K 4824K com.android.phone
  948 23020K 23016K 5864K 4748K com.android.inputmethod.latin
  888 25728K 25724K 5774K 3668K zigot
  977 24100K 24096K 5667K 4340K android.process.acore
...
   59 336K 332K 99K 92K / system / bin / installd
   60 396K 392K 93K 84K / system / bin / keystore
   51 280K 276K 74K 68K / system / bin / servicemanager
   54 256K 252K 69K 64K / system / bin / debuggerd

Di sini Vss dan Rss kolom pada dasarnya berisik (ini adalah ruang alamat lurus ke depan dan penggunaan RAM dari suatu proses, di mana jika Anda menambahkan penggunaan RAM di seluruh proses, Anda mendapatkan jumlah yang sangat besar).

Pss seperti yang telah kita lihat sebelumnya, dan Uss aku s Priv Dirty.

Hal yang menarik untuk dicatat di sini: Pss dan Uss sedikit (atau lebih dari sedikit) berbeda dari apa yang kita lihat meminfo. Mengapa demikian? Yah procrank menggunakan mekanisme kernel yang berbeda untuk mengumpulkan datanya dari meminfo tidak, dan mereka memberikan hasil yang sedikit berbeda. Mengapa demikian? Sejujurnya saya tidak tahu. aku percaya procrank mungkin yang lebih akurat ... tapi sungguh, ini hanya meninggalkan titik: "mengambil info memori yang Anda dapatkan dengan sebutir garam; sering butir yang sangat besar."

Akhirnya ada perintahnya adb shell cat /proc/meminfo yang memberikan ringkasan penggunaan memori keseluruhan sistem. Ada banyak data di sini, hanya beberapa angka pertama yang layak dibahas (dan sisanya yang dimengerti oleh beberapa orang, dan pertanyaan saya tentang beberapa orang tentang mereka sering mengakibatkan penjelasan yang bertentangan):

MemTotal: 395144 kB
MemFree: 184936 kB
Buffer: 880 kB
Tembolok: 84104 kB
SwapCached: 0 kB

MemTotal adalah jumlah total memori yang tersedia untuk kernel dan ruang pengguna (sering kurang dari RAM fisik sebenarnya dari perangkat, karena sebagian dari RAM itu diperlukan untuk radio, buffer DMA, dll).

MemFree adalah jumlah RAM yang tidak digunakan sama sekali. Angka yang Anda lihat di sini sangat tinggi; biasanya pada sistem Android ini hanya beberapa MB, karena kami mencoba menggunakan memori yang tersedia untuk menjaga proses tetap berjalan

Cached adalah RAM yang digunakan untuk cache filesystem dan hal-hal lain seperti itu. Sistem yang khas harus memiliki 20MB atau lebih untuk ini untuk menghindari masuk ke negara paging yang buruk; Android kehabisan memori killer disetel untuk sistem tertentu untuk memastikan bahwa proses latar belakang terbunuh sebelum RAM yang di-cache dikonsumsi terlalu banyak oleh mereka untuk menghasilkan paging seperti itu.


969
2018-02-19 21:44



Ya, Anda bisa mendapatkan info memori secara terprogram dan memutuskan apakah akan melakukan pekerjaan intensif memori.

Dapatkan Ukuran Heap VM dengan menelepon:

Runtime.getRuntime().totalMemory();

Dapatkan Memori VM yang dialokasikan dengan menelepon:

Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();

Dapatkan Batas Ukuran VM Heap dengan menelepon:

Runtime.getRuntime().maxMemory()

Dapatkan Memori Alokasi Asli dengan menelepon:

Debug.getNativeHeapAllocatedSize();

Saya membuat aplikasi untuk mengetahui perilaku OutOfMemoryError dan memantau penggunaan memori.

https://play.google.com/store/apps/details?id=net.coocood.oomresearch

Anda bisa mendapatkan kode sumber di https://github.com/coocood/oom-research


69
2017-12-01 05:49



Ini adalah pekerjaan yang sedang berjalan, tetapi ini yang tidak saya pahami:

ActivityManager activityManager = (ActivityManager) context.getSystemService(ACTIVITY_SERVICE);
MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
activityManager.getMemoryInfo(memoryInfo);

Log.i(TAG, " memoryInfo.availMem " + memoryInfo.availMem + "\n" );
Log.i(TAG, " memoryInfo.lowMemory " + memoryInfo.lowMemory + "\n" );
Log.i(TAG, " memoryInfo.threshold " + memoryInfo.threshold + "\n" );

List<RunningAppProcessInfo> runningAppProcesses = activityManager.getRunningAppProcesses();

Map<Integer, String> pidMap = new TreeMap<Integer, String>();
for (RunningAppProcessInfo runningAppProcessInfo : runningAppProcesses)
{
    pidMap.put(runningAppProcessInfo.pid, runningAppProcessInfo.processName);
}

Collection<Integer> keys = pidMap.keySet();

for(int key : keys)
{
    int pids[] = new int[1];
    pids[0] = key;
    android.os.Debug.MemoryInfo[] memoryInfoArray = activityManager.getProcessMemoryInfo(pids);
    for(android.os.Debug.MemoryInfo pidMemoryInfo: memoryInfoArray)
    {
        Log.i(TAG, String.format("** MEMINFO in pid %d [%s] **\n",pids[0],pidMap.get(pids[0])));
        Log.i(TAG, " pidMemoryInfo.getTotalPrivateDirty(): " + pidMemoryInfo.getTotalPrivateDirty() + "\n");
        Log.i(TAG, " pidMemoryInfo.getTotalPss(): " + pidMemoryInfo.getTotalPss() + "\n");
        Log.i(TAG, " pidMemoryInfo.getTotalSharedDirty(): " + pidMemoryInfo.getTotalSharedDirty() + "\n");
    }
}

Mengapa PID tidak dipetakan ke hasil di activityManager.getProcessMemoryInfo ()? Jelas Anda ingin membuat data yang dihasilkan bermakna, jadi mengapa Google membuatnya sangat sulit untuk mengkorelasikan hasilnya? Sistem saat ini bahkan tidak berfungsi dengan baik jika saya ingin memproses seluruh penggunaan memori karena hasil yang dikembalikan adalah array dari objek android.os.Debug.MemoryInfo, tetapi tidak satu pun dari objek-objek itu benar-benar memberi tahu Anda apa pids yang terkait dengannya. Jika Anda hanya mengirimkan array dari semua pids, Anda tidak akan memiliki cara untuk memahami hasilnya. Seperti yang saya mengerti itu digunakan, itu membuat tidak ada artinya untuk lulus di lebih dari satu pid pada suatu waktu, dan kemudian jika itu yang terjadi, mengapa membuatnya sehingga activityManager.getProcessMemoryInfo () hanya mengambil int array?


48
2017-08-13 18:32



Hackbod adalah salah satu jawaban terbaik di Stack Overflow. Ini menerangi subjek yang sangat tidak jelas. Itu sangat membantu saya.

Sumber daya lain yang sangat bermanfaat adalah video yang harus dilihat ini: Google I / O 2011: Manajemen memori untuk Aplikasi Android


MEMPERBARUI:

Statistik Proses, layanan untuk menemukan cara aplikasi mengelola memori dijelaskan di pos blog Statistik Proses: Memahami Cara Aplikasi Anda Menggunakan RAM oleh Dianne Hackborn:


24
2017-12-21 16:49



Android Studio 0.8.10+ telah memperkenalkan alat yang sangat berguna yang disebut Monitor Memori.

enter image description here

Apa yang baik untuk:

  • Menampilkan memori yang tersedia dan digunakan dalam grafik, dan pengumpulan sampah   kejadian dari waktu ke waktu.
  • Dengan cepat menguji apakah kelambatan aplikasi mungkin   terkait dengan acara pengumpulan sampah yang berlebihan.
  • Cepat menguji   apakah aplikasi macet mungkin terkait dengan kehabisan memori.

enter image description here

Gambar 1. Memaksa acara GC (Pengumpulan Sampah) di Android Memory Monitor

Anda dapat memiliki banyak informasi bagus tentang konsumsi RAM real-time aplikasi Anda dengan menggunakannya.


19
2017-08-12 12:40



1) Saya kira tidak, setidaknya tidak dari Jawa.
2)

ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
MemoryInfo mi = new MemoryInfo();
activityManager.getMemoryInfo(mi);
Log.i("memory free", "" + mi.availMem);

16
2018-02-19 17:31



Kami menemukan bahwa semua cara standar untuk mendapatkan memori total dari proses saat ini memiliki beberapa masalah.

  • Runtime.getRuntime().totalMemory(): hanya mengembalikan memori JVM
  • ActivityManager.getMemoryInfo(), Process.getFreeMemory() dan yang lainnya berdasarkan /proc/meminfo - mengembalikan info memori tentang semua proses yang digabungkan (mis. android_util_Process.cpp)
  • Debug.getNativeHeapAllocatedSize() - menggunakan mallinfo() yang mengembalikan informasi tentang alokasi memori yang dilakukan oleh malloc() dan hanya fungsi terkait (lihat android_os_Debug.cpp)
  • Debug.getMemoryInfo() - Melakukan pekerjaan tetapi terlalu lambat. Dibutuhkan sekitar 200ms di Nexus 6 untuk satu panggilan. Overhead kinerja membuat fungsi ini tidak berguna bagi kita seperti yang kita sebut secara teratur dan setiap panggilan cukup terlihat (lihat android_os_Debug.cpp)
  • ActivityManager.getProcessMemoryInfo(int[]) - panggilan Debug.getMemoryInfo() secara internal (lihat ActivityManagerService.java)

Akhirnya, kami akhirnya menggunakan kode berikut:

const long pageSize = 4 * 1024; //`sysconf(_SC_PAGESIZE)`
string stats = File.ReadAllText("/proc/self/statm");
var statsArr = stats.Split(new [] {' ', '\t', '\n'}, 3);

if( statsArr.Length < 2 )
    throw new Exception("Parsing error of /proc/self/statm: " + stats);

return long.Parse(statsArr[1]) * pageSize;

Ia kembali VmRSS metrik. Anda dapat menemukan detail lebih lanjut tentang ini di sini: satu, dua dan tiga.


P.S. Saya perhatikan bahwa tema masih memiliki kekurangan snipet kode yang sebenarnya dan sederhana tentang bagaimana caranya memperkirakan penggunaan memori pribadi dari proses jika kinerja bukanlah persyaratan penting:

Debug.MemoryInfo memInfo = new Debug.MemoryInfo();
Debug.getMemoryInfo(memInfo);
long res = memInfo.getTotalPrivateDirty();

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) 
    res += memInfo.getTotalPrivateClean(); 

return res * 1024L;

2
2017-08-14 02:02