Kaip išmokti savo programos atminties naudojimą „Android“?

Kaip programinėje programoje rasti „Android“ programoje naudojamą atmintį?

Tikiuosi, kad yra būdas tai padaryti. Be to, kaip gauti nemokamą telefono atmintį?

728
19 февр. Nustatė Andrea Baccega vasario 19 d 2010-02-19 20:12 '10, 20:12, 2010-02-19 20:12
@ 8 atsakymai

Atkreipkite dėmesį, kad atminties naudojimas šiuolaikinėse operacinėse sistemose, tokiose kaip Linux, yra labai sudėtinga ir sunkiai suprantama sritis. Iš tiesų, tikimybė, kad jūs teisingai interpretuosite viską, ką gaunate, yra labai mažos. (Beveik kiekvieną kartą, kai žiūriu į atminties naudojimo numerius su kitais inžinieriais, visuomet diskutuojama apie tai, ką jie iš tikrųjų reiškia, o tai tik nulemia neribotą išvadą.)

Pastaba: dabar mes turime daug išsamesnę taikomojo atminties valdymo dokumentaciją, kuri apima daugumą čia esančių dalykų ir daugiau su „Android“ būsena.

Visų pirma, galbūt perskaitykite paskutinę šio straipsnio dalį, kurioje aptariama, kaip valdoma „Android“ atmintis:

API paslaugos keičiasi pradedant „Android 2.0“

ActivityManager.getMemoryInfo() yra mūsų aukščiausio lygio API, skirta peržiūrėti bendrai naudojamą atmintį. Tai iš esmės padeda nustatyti, kaip glaudžiai sistema priartėja prie atminties trūkumo foniniams procesams, todėl reikia pradėti žudyti būtinus procesus, pvz., Paslaugas. Grynoms „Java“ programoms tai turėtų būti mažai naudinga, nes „Java“ krūvos apribojimas iš dalies yra iš dalies siekiant išvengti to, kad viena programa negali pabrėžti sistemos šiuo klausimu.

Pereinant prie žemesnio lygio, galite naudoti derinimo API, kad gautumėte informacijos apie atminties naudojimą branduolio lygiu: android.os.Debug.MemoryInfo

Atkreipkite dėmesį, kad nuo 2.0 versijos taip pat yra API, ActivityManager.getProcessMemoryInfo , kad gautumėte šią informaciją apie kitą procesą: ActivityManager.getProcessMemoryInfo (int [])

Tai grąžina žemo lygio „MemoryInfo“ struktūrą su visais šiais duomenimis:

   public int dalvikPss;  public int dalvikPrivateDirty;  public int dalvikSharedDirty;  public int nativePss;  public int nativePrivateDirty;  public int nativeSharedDirty;  public int otherPss;  public int otherPrivateDirty;  public int otherSharedDirty; 

Bet kaip skirtumas tarp „ SharedDirty , „ PrivateDirty ir „ SharedDirty ... dabar prasideda linksmybė.

Dauguma atminties „Android“ (ir „Linux“ sistemose) iš tikrųjų yra dalijamasi keliais procesais. Taigi, kiek atminties procesas naudoja, yra neaiškus. Įrašykite į šį diską (ne jau nekalbant apie keitimą, kurį nenaudojame „Android“), ir tai dar mažiau aišku.

Taigi, jei atsiimtumėte visą fizinę atmintį, parodytą kiekviename procese, ir pridėkite visus procesus, tikriausiai baigsite skaičių, kuris yra daug didesnis nei faktinė RAM.

Pss numeris yra metrika, kurią apskaičiuoja branduolys, kuriame atsižvelgiama į atminties pasidalijimą - iš esmės kiekvienas proceso RAM puslapis yra suskirstytas pagal kitų procesų, kurie taip pat naudoja šį puslapį, skaičių. Taigi, galite (teoriškai) pridėti pss prie visų procesų, kad pamatytumėte bendrą RAM, kurią jie naudoja, ir palyginkite pss tarp procesų, kad gautumėte apytikrę jų santykinio svorio idėją.

Kitas įdomus rodiklis yra „ PrivateDirty , kuris iš esmės yra RAM kiekis, kuris negali būti iškrautas ant disko (to nepalaiko tie patys duomenys diske) ir nėra dalijamasi su kitais procesais. Kitas būdas pažvelgti į tai yra RAM, kuri bus prieinama sistemai, kai šis procesas palieka (ir greičiausiai greitai įsijungs į talpyklas ir kitus jų naudojimo būdus).

Tai beveik visi SDK API. Tačiau tai galite padaryti kaip kūrėjas naudodami savo prietaisą.

Naudojant adb , galite gauti daug informacijos apie jūsų sistemos veikimą. Įprasta „ adb shell dumpsys meminfo , kuri kiekvieną Java procesą, kuriame yra aukščiau pateikta informacija, ir daugelį kitų dalykų išsiskiria daugybė atminties naudojimo informacijos. Taip pat galite naudoti vieno proceso pavadinimą arba pid, kad pamatytumėte, pvz., „ adb shell dumpsys meminfo system suteikia man sistemos procesą:

 ** MEMINFO į pid 890 [sistema] ** gimtoji dalvik kita dydis: 10940 7047 N / A 17987skiriama: 8943 5516 N / A 14459 nemokamai: 336 1531 N / A 1867(Pss): 4585 9282 11916 25783   (bendras purvinas): 2184 3596 916 6696 (priv dirty): 4504 5956 7456 17916  ObjektaiPeržiūrų: 149 ViewRoots: 4  AppContexts: 13 Veikla: 0   Turtas: 4 turto turėtojai: 4Vietiniai rišikliai: 141 proxy rišikliai: 158 Mirties gavėjai: 49  OpenSSL lizdai: 0  SQL krūva: 205 dbFiles: 0numPagers: 0 inactivePageKB: 0 ActivePageKB: 0

Viršutinė dalis yra pagrindinis, kur size yra bendras dydis konkrečios krūvos adresų erdvėje, allocated faktinių pasiskirstymų kb, kad krūva mano, kad ji yra free - likusi kb laisva krūva turi papildomų paskirstymų, o Pss ir priv dirty yra tokie patys, kaip aptarta anksčiau, konkrečių puslapių, susijusių su kiekviena krūva.

Jei tiesiog norite pažvelgti į atminties naudojimą visuose procesuose, galite naudoti adb shell procrank . Šios sistemos išvestis toje pačioje sistemoje yra tokia:

   PID Vss Rss Pss Naudoja 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 zigotas   977 24100K 24096K 5667K 4340K android.process.acore ...59 336K 332K 99K 92K / system / bin / installd60 396K 392K 93K 84K / sistema / dėžė / keystore51 280K 276K 74K 68K / sistema / bin / servicemanager54 256K 252K 69K 64K / system / bin / debuggerd

Čia „ Vss ir „ Rss stulpeliai dažniausiai Vss triukšmas (tai tiesioginė adresų erdvė ir RAM naudojimas procesuose, kur, jei pridėsite RAM prie procesų, gausite juokingai didelę sumą).

Pss , kaip matėme anksčiau, ir Uss - priv dirty .

Čia įdomu pastebėti: „ Pss ir „ Uss šiek tiek (arba šiek tiek daugiau) nei tai, ką matėme „ meminfo . Kodėl taip? Na, procrank naudoja kitokį branduolio mechanizmą, kad surinkti duomenis nei meminfo , ir jie šiek tiek skiriasi. Kodėl taip? Sąžiningai, aš neturiu idėjos. Manau, kad procrank gali būti tikslesnis ... bet iš tikrųjų jis palieka tašką: „imkite bet kokią informaciją apie atmintį su druskos grūdais, dažnai labai dideliais grūdais“.

Galiausiai, yra adb shell cat /proc/meminfo , kurioje trumpai aprašomas bendras atminties naudojimas sistemoje. Yra daug duomenų, bet tik pirmieji keli numeriai, kuriuos verta aptarti (o kiti - mažai žmonių, o mano klausimai apie tuos kelis žmones dažnai sukelia prieštaringus paaiškinimus apie juos):

 MemTotal: 395144 kB MemFree: 184936 kB Buferiai: 880 kB Saugoma talpykla: 84104 kB SwapCached: 0 kB

MemTotal yra bendras atminties kiekis, prieinamas branduoliui ir naudotojo vietai (dažnai mažesnis už faktinę fizinę įrenginio atmintį, nes šios atminties dalis reikalinga radijo, DMA buferiams ir pan.).

MemFree yra RAM, kuris visai nenaudojamas. Čia matomas labai didelis skaičius; kaip taisyklė, „Android“ sistemoje ji bus tik keli MB, nes bandome naudoti turimą atmintį, kad palaikytume atliktus procesus

Cached talpykla yra RAM, naudojama failų sistemos talpykloms ir kitiems tokiems dalykams. Tipiškoms sistemoms užtrukti reikės 20 MB, kad būtų išvengta blogos būsenos paieškos; „Android“ žudikas žudikas iš atminties yra sukonfigūruotas konkrečiai sistemai, užtikrinančiai, kad foniniai procesai būtų nužudyti prieš talpykloje esančią atmintį per daug jų suvartojant, kad būtų pasiektas toks paieškos skambutis.

955
20 февр. hackbod atsakymas 20 vas. 2010-02-20 00:44 '10 - 0:44 2010-02-20 00:44

Taip, informaciją apie atmintį galite gauti programiškai ir nuspręsti, ar dirbti intensyviai.

Gauti VM krūvos dydį skambindami:

 Runtime.getRuntime().totalMemory(); 

Gaukite specialią VM atmintį skambindami:

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

Gauti VM krūvos dydžio apribojimą skambindami:

border=0
 Runtime.getRuntime().maxMemory() 

Gaukite vidinę paskirstytą atmintį skambindami:

 Debug.getNativeHeapAllocatedSize(); 

Pateikiau programą, kad išsiaiškintumėte „OutOfMemoryError“ elgesį ir stebėjau atminties naudojimą.

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

Šaltinį galite gauti adresu https://github.com/coocood/oom-research

68
01 дек. atsakymas pateikiamas 01 d. 2012-12-01 08:49 '12 at 8:49 2012-12-01 08:49

Tai yra darbas, kuris šiuo metu vyksta, bet tai nesuprantu:

 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"); } } 

Kodėl PID nėra susietas su rezultatu veiklojeManager.getProcessMemoryInfo ()? Akivaizdu, kad norite, kad gauti duomenys būtų prasmingi, kodėl „Google“ taip sunkiai suderino rezultatus? Dabartinė sistema net neveikia, jei noriu valdyti visą atminties naudojimą, nes grąžinamas rezultatas yra „android.os.Debug.MemoryInfo“ objektų masyvas, tačiau nė vienas iš šių objektų nesako jums, kokie ryšiai yra susiję. Jei paprasčiausiai pereisite prie visų „pids“ masyvo, negalėsite suprasti rezultatų. Kiek aš suprantu, šis naudojimas neleidžia perkelti daugiau nei vieno pid laiko vienu metu, o tada, jei taip, kodėl padaryti jį taip, kad activityManager.getProcessMemoryInfo () priimtų tik int masę?

47
13 авг. Ryan Beesley atsakymas rugpjūčio 13 d 2010-08-13 21:32 '10 ne 21:32 2010-08-13 21:32

Hackbod yra vienas iš geriausių atsakymų į „Stack Overflow“. Jis nušviečia labai neaiškią temą. Tai tikrai padėjo man.

Kitas labai naudingas šaltinis yra reikalingas vaizdo įrašas: „ Google I / O 2011“: „Android“ programų atminties valdymas


UPDATE:

Procesų statistika - paslauga, skirta sužinoti, kaip jūsų programa valdo atmintį, yra paaiškinta dienoraščio įraše. Procesų statistika: suprasti, kaip jūsų programa naudoja RAM iš Dianne Hackborn:

23
21 дек. Atsakymą pateikė Xavi Gil . 2011-12-21 19:49 '11, 19:49, 2011-12-21 19:49

„Android Studio 0.8.10+“ pristatė neįtikėtinai naudingą įrankį, vadinamą „ Memory Monitor“ .

2019

12 авг. atsakymas suteiktas Machado 12 rug. 2015-08-12 15:40 '15 15:40 2015-08-12 15:40

1) Manau, bent jau ne iš „Java“.
2)

 ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE); MemoryInfo mi = new MemoryInfo(); activityManager.getMemoryInfo(mi); Log.i("memory free", "" + mi.availMem); 
16
19 февр. Atsakymą pateikė yanchenko 19 vasaris 2010-02-19 20:31 '10, 20:31, 2010-02-19 20:31

Mes nustatėme, kad visi standartiniai būdai, kaip gauti visišką dabartinio proceso atmintį, turi tam tikrų problemų.

  • Runtime.getRuntime().totalMemory() : grąžina tik JVM atmintį
  • ActivityManager.getMemoryInfo() , Process.getFreeMemory() ir visa kita, pagrįsta /proc/meminfo - grąžina atminties informaciją apie visus procesus (pvz., Android_util_Process.cpp )
  • Debug.getNativeHeapAllocatedSize() - naudoja mallinfo() , kuris grąžina informaciją apie atminties paskirstymą, kurį atlieka tik malloc() ir susijusios funkcijos (žr. Android_os_Debug.cpp )
  • Debug.getMemoryInfo() - atlieka darbą, bet jis yra per lėtas. Nexus 6 trunka apie 200 ms vienam skambučiui. Priklausomai nuo to, kaip mes jį vadiname reguliariai, ši funkcija mums nenaudinga, o kiekvienas skambutis yra gana pastebimas (žr. Android_os_Debug.cpp )
  • ActivityManager.getProcessMemoryInfo(int[]) - viduje skambina Debug.getMemoryInfo() (žr. ActivityManagerService.java )

Galiausiai baigėme naudoti šį kodą:

vienas , du ir trys . 


PS Aš pastebėjau, kad objektas vis dar trūksta faktinio ir paprasto kodo, kaip įvertinti asmeninės atminties naudojimą privačioje atmintyje, jei našumas nėra esminis reikalavimas:

2
14 авг. Dmitrijus Šesterkinas atsakė 14 d. 2017-08-14 05:02 '17 at 5:02 2017-08-14 05:02

Aukščiau yra daug atsakymų, kurie tikrai padės jums, bet aš (po 2 dienų nuo adb atminties įrankių gavimo ir tyrimo) manau, kad galiu padėti mano nuomonei .

Kaip sako Hackbod: Taigi, jei pasirinkote visas fizines RAM, kurios buvo rodomos kiekviename procese, ir pridedate visus procesus, tikriausiai baigsite skaičių, kuris yra daug didesnis nei faktinė RAM. , todėl jūs negalite gauti tikslaus atminties kiekio.

Bet jūs galite kreiptis į ją su kažkokia logika. Ir aš jums pasakysiu, kaip ..

Yra keletas API, pvz., „ android.os.Debug.MemoryInfo ir „ ActivityManager.getMemoryInfo() , kuriuos jau galėjote perskaityti ir naudoti, tačiau pasakysiu apie kitą (netiesioginę) konversiją

Taigi, pirmiausia turite būti root vartotojas, kad jis veiktų. Prisijunkite prie konsolės kaip šaknies, vykdydami su procesą ir gaudami output and input stream . Tada perduokite id\n (tipas) į „Ouputstream“ ir parašykite jį apdoroti išvestį. Jei gausite įvesties srautą, kuriame yra uid=0 , esate šaknis.

Dabar čia yra logika, kurią naudosite pirmiau aprašytame procese.

Kai gausite „ouputstream“ procesą , siųskite komandą (procrank, dumpsys meminfo ir tt), o ne id, ir gaukite jo inputstream ir skaitymo, išsaugokite srautą baitais, char ir tt naudokite neapdorotus duomenis.

:

 <uses-permission android:name="android.permission.FACTORY_TEST"/> 

Patikrinkite, ar esate root vartotojas:

 try { // 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")) { // yes sir you are root user } } } catch (Exception e) { } 

Paleiskite su komandą

 try { // 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(); } } catch (Exception e) { } 

logcat: 2019

20 февр. Atsakymas pateikiamas Mohit 20 vasario mėn. 2018-02-20 15:37 '18, 15:37 pm 2018-02-20 15:37

Kiti klausimai apie „ žymes „ arba Užduoti klausimą