Bagaimana saya dapat menemukan memori yang digunakan pada aplikasi Android saya, secara terprogram?
Saya harap ada cara untuk melakukannya. Plus, bagaimana cara mendapatkan memori bebas telepon juga?
Bagaimana saya dapat menemukan memori yang digunakan pada aplikasi Android saya, secara terprogram?
Saya harap ada cara untuk melakukannya. Plus, bagaimana cara mendapatkan memori bebas telepon juga?
Jawaban:
Perhatikan bahwa penggunaan memori pada sistem operasi modern seperti Linux adalah bidang yang sangat rumit dan sulit dipahami. Bahkan kemungkinan Anda benar-benar menafsirkan angka apa pun yang Anda dapatkan sangat rendah. (Cukup banyak setiap kali saya melihat nomor penggunaan memori dengan insinyur lain, selalu ada diskusi panjang tentang apa yang sebenarnya berarti bahwa hanya menghasilkan kesimpulan yang samar-samar.)
Catatan: kami sekarang memiliki dokumentasi yang jauh lebih luas tentang Mengelola Memori Aplikasi Anda yang mencakup banyak materi di sini dan lebih mutakhir 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 tingkat tertinggi kami untuk melihat penggunaan memori secara keseluruhan. Ini sebagian besar ada untuk membantu aplikasi mengukur seberapa dekat sistem tidak memiliki memori lebih untuk proses latar belakang, sehingga perlu mulai membunuh proses yang diperlukan seperti layanan. Untuk aplikasi Java murni, ini seharusnya tidak banyak berguna, karena batas heap Java ada sebagian untuk menghindari satu aplikasi dari dapat menekankan sistem ke titik ini.
Menuju level yang lebih rendah, Anda dapat menggunakan Debug API untuk mendapatkan informasi level 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;
Tapi seperti apa perbedaan antara Pss
, PrivateDirty
dan SharedDirty
... baik sekarang menyenangkan dimulai.
Banyak memori di Android (dan sistem Linux pada umumnya) sebenarnya dibagi di banyak proses. Jadi berapa banyak memori yang digunakan suatu proses benar-benar tidak jelas. Tambahkan paging keluar ke disk (apalagi swap yang tidak kita gunakan pada Android) dan itu bahkan kurang jelas.
Jadi jika Anda mengambil semua RAM fisik yang benar-benar dipetakan ke dalam setiap proses, dan menambahkan semua proses, Anda mungkin akan berakhir dengan angka yang jauh lebih besar daripada total RAM yang sebenarnya.
The Pss
nomor adalah metrik ini menghitung kernel yang memperhitungkan berbagi memori akun - pada dasarnya setiap halaman RAM dalam proses skala oleh rasio jumlah proses lain juga menggunakan halaman tersebut. Dengan cara ini Anda dapat (secara teori) menambahkan pss di semua proses untuk melihat total RAM 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-paging ke disk (tidak didukung oleh data yang sama pada disk), dan tidak dibagi dengan proses lain. 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 lainnya).
Cukup banyak SDK API untuk ini. Namun ada lebih banyak yang dapat Anda lakukan sebagai pengembang dengan perangkat Anda.
Menggunakan adb
, ada banyak informasi yang bisa Anda dapatkan tentang penggunaan memori sistem yang sedang berjalan. Yang umum adalah perintah 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 dapat menempel pada nama atau pid dari satu proses untuk melihat, misalnya adb shell dumpsys meminfo system
memberi saya proses sistem:
** MEMINFO di pid 890 [sistem] ** dalvik asli total lainnya ukuran: 10940 7047 N / A 17987 dialokasikan: 8943 5516 N / A 14459 gratis: 336 1531 N / A 1867 (Mz): 4585 9282 11916 25783 (kotor bersama): 2184 3596 916 6696 (Priv dirty): 4504 5956 7456 17916 Benda Views: 149 ViewRoots: 4 AppContexts: 13 Aktivitas: 0 Aset: 4 Aset Manajer: 4 Pengikat Lokal: 141 Pengikat Proksi: 158 Penerima Kematian: 49 Soket OpenSSL: 0 SQL heap: 205 dbFiles: 0 numPagers: 0 tidak aktifPageKB: 0 activePageKB: 0
Bagian atas adalah yang utama, di mana size
ukuran total dalam ruang alamat heap tertentu, allocated
adalah kb dari alokasi aktual yang menurut heap, free
adalah sisa kb yang bebas dari heap untuk alokasi tambahan, dan pss
dan priv dirty
sama seperti 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 dari 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 zygote 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 kolom Vss
dan Rss
pada dasarnya berisik (ini adalah ruang alamat langsung 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 kita lihat sebelumnya, dan Uss
sekarang Priv Dirty
.
Hal yang menarik untuk diperhatikan di sini: Pss
dan Uss
sedikit (atau lebih dari sedikit) berbeda dari apa yang kami lihat meminfo
. Mengapa demikian? Well procrank menggunakan mekanisme kernel yang berbeda untuk mengumpulkan datanya meminfo
, dan mereka memberikan hasil yang sedikit berbeda. Mengapa demikian? Jujur saya tidak tahu. Saya percaya procrank
mungkin yang lebih akurat ... tapi sungguh, ini hanya meninggalkan titik: "ambil info memori yang Anda dapatkan dengan sebutir garam; sering kali butir yang sangat besar."
Akhirnya ada perintah adb shell cat /proc/meminfo
yang memberikan ringkasan dari keseluruhan penggunaan memori sistem. Ada banyak data di sini, hanya beberapa angka pertama yang layak dibahas (dan yang tersisa hanya dimengerti oleh beberapa orang, dan pertanyaan saya tentang beberapa orang itu tentang mereka sering menghasilkan penjelasan yang saling 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 (seringkali 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. Jumlah 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 sistem file dan hal-hal lain semacam itu. Sistem khas perlu memiliki 20MB atau lebih untuk ini agar tidak masuk ke kondisi halaman yang buruk; Android out of memory killer disetel untuk sistem tertentu untuk memastikan bahwa proses latar belakang dimatikan sebelum RAM yang di-cache dikonsumsi terlalu banyak oleh mereka untuk menghasilkan paging seperti itu.
Ya, Anda dapat memperoleh informasi memori secara terprogram dan memutuskan apakah akan melakukan pekerjaan yang intensif memori.
Dapatkan Ukuran VM Heap dengan menelepon:
Runtime.getRuntime().totalMemory();
Dapatkan Memori VM yang dialokasikan dengan menelepon:
Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
Dapatkan VM Heap Size Limit dengan menelepon:
Runtime.getRuntime().maxMemory()
Dapatkan Memori Alokasi Asli dengan menelepon:
Debug.getNativeHeapAllocatedSize();
Saya membuat aplikasi untuk mengetahui perilaku OutOfMemoryError dan memonitor 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
Ini adalah pekerjaan yang sedang berjalan, tapi ini yang saya tidak mengerti:
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 menjadikan data yang dihasilkan bermakna, jadi mengapa Google membuatnya sangat sulit untuk menghubungkan hasil? 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 ada objek yang benar-benar memberi tahu Anda apa yang terkait dengan pids. Jika Anda hanya memasukkan array dari semua tawaran, Anda tidak akan dapat memahami hasilnya. Seperti yang saya pahami penggunaannya, tidak ada artinya untuk melewatkan lebih dari satu pid pada satu waktu, dan kemudian jika itu masalahnya, mengapa membuatnya jadi activityManager.getProcessMemoryInfo () hanya membutuhkan array int?
Hackbod's adalah salah satu jawaban terbaik di Stack Overflow. Ini menyoroti subjek yang sangat tidak jelas. Itu banyak membantu saya.
Sumber lain yang sangat membantu adalah video yang harus dilihat ini: Google I / O 2011: Manajemen memori untuk Aplikasi Android
MEMPERBARUI:
Process Stats, layanan untuk mengetahui bagaimana aplikasi Anda mengelola memori dijelaskan di posting blog Process Stats: Memahami Bagaimana Aplikasi Anda Menggunakan RAM oleh Dianne Hackborn:
Android Studio 0.8.10+ telah memperkenalkan alat yang sangat berguna yang disebut Memory Monitor .
Apa manfaatnya untuk:
- Menampilkan memori yang tersedia dan bekas dalam grafik, dan aktivitas pengumpulan sampah seiring waktu.
- Dengan cepat menguji apakah kelambatan aplikasi mungkin terkait dengan acara pengumpulan sampah yang berlebihan.
- Dengan cepat menguji apakah aplikasi mogok mungkin terkait dengan kehabisan memori.
Gambar 1. Memaksa acara GC (Pengumpulan Sampah) di Android Memory Monitor
Anda dapat memiliki banyak informasi bagus tentang konsumsi waktu nyata RAM aplikasi Anda dengan menggunakannya.
1) Saya rasa tidak, paling tidak dari Jawa.
2)
ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
MemoryInfo mi = new MemoryInfo();
activityManager.getMemoryInfo(mi);
Log.i("memory free", "" + mi.availMem);
Kami menemukan bahwa semua cara standar untuk mendapatkan memori total dari proses saat ini memiliki beberapa masalah.
Runtime.getRuntime().totalMemory()
: hanya mengembalikan memori JVMActivityManager.getMemoryInfo()
, Process.getFreeMemory()
dan apa pun 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 fungsi terkait saja (lihat android_os_Debug.cpp )Debug.getMemoryInfo()
- Melakukan pekerjaan tetapi terlalu lambat. Dibutuhkan sekitar 200ms pada Nexus 6 untuk satu panggilan. Kinerja overhead membuat fungsi ini tidak berguna bagi kami karena kami menyebutnya secara teratur dan setiap panggilan cukup terlihat (lihat android_os_Debug.cpp )ActivityManager.getProcessMemoryInfo(int[])
- panggilan Debug.getMemoryInfo()
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 mengembalikan metrik VmRSS . Anda dapat menemukan detail lebih lanjut di sini: satu , dua dan tiga .
PS Saya perhatikan bahwa temanya masih kekurangan potongan kode aktual dan sederhana tentang cara memperkirakan penggunaan memori pribadi dari proses jika kinerjanya bukan 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;
Di android studio 3.0 mereka telah memperkenalkan android-profiler untuk membantu Anda memahami bagaimana aplikasi Anda menggunakan CPU, memori, jaringan, dan sumber daya baterai.
https://developer.android.com/studio/profile/android-profiler
Ada banyak jawaban di atas yang pasti akan membantu Anda tetapi (setelah 2 hari mampu dan meneliti alat memori adb) saya pikir saya dapat membantu dengan pendapat saya juga.
Seperti yang dikatakan Hackbod: Jadi, jika Anda mengambil semua RAM fisik yang benar-benar dipetakan ke dalam setiap proses, dan menambahkan semua proses, Anda mungkin akan berakhir dengan angka yang jauh lebih besar daripada total RAM yang sebenarnya. jadi tidak ada cara Anda bisa mendapatkan jumlah memori yang tepat per proses.
Tapi Anda bisa mendekatinya dengan beberapa logika..dan saya akan memberitahu caranya ..
Ada beberapa API seperti
android.os.Debug.MemoryInfo
danActivityManager.getMemoryInfo()
disebutkan di atas yang mungkin sudah Anda baca dan gunakan tetapi saya akan berbicara tentang cara lain
Jadi pertama-tama Anda harus menjadi pengguna root untuk membuatnya berfungsi. Masuk ke konsol dengan hak istimewa root dengan mengeksekusi su
dalam proses dan mendapatkannya output and input stream
. Kemudian id\n
masukkan (masukkan) dalam ouputstream dan tulis untuk memproses output, Jika akan mendapatkan inputstream yang berisi uid=0
, Anda adalah pengguna root.
Sekarang di sini adalah logika yang akan Anda gunakan dalam proses di atas
Ketika Anda mendapatkan ouputstream dari proses, lewati perintah Anda (procrank, dumpsys meminfo, dll ...) dengan \n
alih - alih id dan dapatkan inputstream
dan baca, simpan aliran dalam byte [], char [] dll. Gunakan raw mentah..dan Anda selesai !!!!!
izin:
<uses-permission android:name="android.permission.FACTORY_TEST"/>
Periksa apakah Anda pengguna root:
// su command to get root access
Process process = Runtime.getRuntime().exec("su");
DataOutputStream dataOutputStream =
new DataOutputStream(process.getOutputStream());
DataInputStream dataInputStream =
new DataInputStream(process.getInputStream());
if (dataInputStream != null && dataOutputStream != null) {
// write id to console with enter
dataOutputStream.writeBytes("id\n");
dataOutputStream.flush();
String Uid = dataInputStream.readLine();
// read output and check if uid is there
if (Uid.contains("uid=0")) {
// you are root user
}
}
Jalankan perintah Anda dengan su
Process process = Runtime.getRuntime().exec("su");
DataOutputStream dataOutputStream =
new DataOutputStream(process.getOutputStream());
if (dataOutputStream != null) {
// adb command
dataOutputStream.writeBytes("procrank\n");
dataOutputStream.flush();
BufferedInputStream bufferedInputStream =
new BufferedInputStream(process.getInputStream());
// this is important as it takes times to return to next line so wait
// else you with get empty bytes in buffered stream
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// read buffered stream into byte,char etc.
byte[] bff = new byte[bufferedInputStream.available()];
bufferedInputStream.read(bff);
bufferedInputStream.close();
}
}
Anda mendapatkan data mentah dalam satu string dari konsol alih-alih dalam beberapa contoh dari API apa pun, yang rumit untuk disimpan karena Anda harus memisahkannya secara manual .
Ini hanya mencoba, tolong sarankan saya jika saya melewatkan sesuatu