Wykrywanie rozmiaru stosu aplikacji w systemie Android

Jak programowo wykrywać rozmiar sterty aplikacji dostępnej dla aplikacji na Androida?

Słyszałem, że istnieje funkcja, która robi to w późniejszych wersjach SDK. W każdym razie szukam rozwiązania, które działa na 1,5 i więcej.

Author: hpique, 2010-04-13

9 answers

Istnieją dwa sposoby myślenia o frazie "Dostępny rozmiar stosu aplikacji":

  1. Ile sterty może używać moja aplikacja, zanim zostanie wywołany twardy błąd? I

  2. Ile kupy powinna używać moja aplikacja, biorąc pod uwagę ograniczenia wersji systemu operacyjnego Android i sprzętu urządzenia użytkownika?

Istnieje inna metoda określania każdego z powyższych.

Dla pozycji 1 powyżej: maxMemory()

Które można wywołać (np. w metodzie głównej aktywności onCreate()) w następujący sposób:

Runtime rt = Runtime.getRuntime();
long maxMemory = rt.maxMemory();
Log.v("onCreate", "maxMemory:" + Long.toString(maxMemory));

Ta metoda mówi ci ile łącznie bajtów sterty Twojej aplikacji jest dozwolone do użycia.

Dla pozycji 2 powyżej: getMemoryClass()

Które można wywołać w następujący sposób:

ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
int memoryClass = am.getMemoryClass();
Log.v("onCreate", "memoryClass:" + Integer.toString(memoryClass));

Ta metoda mówi w przybliżeniu, ile megabajtów sterty powinna użyć Twoja aplikacja, jeśli chce prawidłowo przestrzegać ograniczeń obecnego urządzenia i praw innych aplikacji biegać bez wielokrotnego zmuszania do onStop() / onResume() cykl, gdy są niegrzecznie wypłukane z pamięci, podczas gdy Twoja aplikacja elephantine kąpie się w jacuzzi z Androidem.

To rozróżnienie nie jest wyraźnie udokumentowane, o ile wiem, ale przetestowałem tę hipotezę na pięciu różnych urządzeniach z Androidem (patrz poniżej) i potwierdziłem, ku własnej satysfakcji, że jest to prawidłowa interpretacja.

Dla standardowej wersji Androida, maxMemory() zwróci zazwyczaj mniej więcej to samo liczba megabajtów wskazana w getMemoryClass() (tj. około milion razy większa od tej ostatniej wartości).

Jedyna sytuacja (której jestem świadomy), dla której dwie metody mogą się różnić, jest na zakorzenionym urządzeniu z wersją Androida, taką jak CyanogenMod, która pozwala użytkownikowi ręcznie wybrać jak duży rozmiar sterty powinien być dozwolony dla każdej aplikacji. Na przykład w CM ta opcja jest wyświetlana w obszarze "Ustawienia CyanogenMod" / "wydajność" / "rozmiar sterty maszyny wirtualnej".

UWAGA: BE Pamiętaj, że Ręczne Ustawienie tej wartości może spowodować bałagan w systemie, zwłaszcza jeśli wybierzesz wartość mniejszą niż normalna dla urządzenia.

Oto wyniki mojego testu pokazujące wartości zwracane przez maxMemory() i getMemoryClass() dla czterech różnych urządzeń z CyanogenMod, używając dwóch różnych (ręcznie ustawianych) wartości sterty dla każdego:

  • G1:
    • z ustawionym rozmiarem sterty VM na 16MB:
      • maxMemory: 16777216
      • getMemoryClass: 16
    • Z VM Rozmiar sterty ustawiony na 24MB:
      • maxmemory: 25165824
      • getMemoryClass: 16
  • Moto Droid:
    • With VM Heap Size set to 24MB:
      • maxmemory: 25165824
      • getMemoryClass: 24
    • z ustawionym rozmiarem sterty VM na 16MB:
      • maxMemory: 16777216
      • getMemoryClass: 24
  • Nexus One:
    • With VM Heap size set to 32MB:
      • maxMemory: 33554432
      • getMemoryClass: 32
    • With VM Heap size set to 24MB:
      • maxmemory: 25165824
      • getMemoryClass: 32
  • Viewsonic GTab:
    • z ustawionym rozmiarem sterty VM na 32:
      • maxmemory: 33554432
      • getMemoryClass: 32
    • z ustawionym rozmiarem sterty VM na 64:
      • maxMemory: 67108864
      • getMemoryClass: 32

W oprócz powyższego, testowałem na tablecie Novo7 Paladin z Ice Cream Sandwich. To była zasadniczo wersja zapasów ICS, z wyjątkiem tego, że mam zakorzenione tablet poprzez prosty proces, który nie zastępuje całego systemu operacyjnego, a w szczególności nie zapewnia interfejsu, który pozwoliłby rozmiar sterty być ręcznie regulowane.

Dla tego urządzenia, oto wyniki:

  • Novo7
    • maxmemory: 62914560
    • getMemoryClass: 60

Również (per Kishore w komentarzu poniżej):

  • HTC One X
    • maxMemory: 67108864
    • getMemoryClass: 64

I (za komentarz akauppiego):

  • Samsung Galaxy Core Plus
    • maxMemory: (Nie podano w komentarzu)
    • getMemoryClass: 48
    • largeMemoryClass: 128

Za komentarz od cmcromance:

  • Galaxy S3 (Jelly Fasola) duża kupa
    • maxmemory: 268435456
    • getMemoryClass: 64

I (za komentarze):

  • LG Nexus 5 (4.4.3) normal
    • maxMemory: 201326592
    • getMemoryClass: 192
  • LG Nexus 5 (4.4.3) large heap
    • maxmemory: 536870912
    • getMemoryClass: 192
  • Galaxy Nexus (4.3) normal
    • maxmemory: 100663296
    • getMemoryClass: 96
  • Galaxy Nexus (4.3) duża sterta
    • maxmemory: 268435456
    • getMemoryClass: 96
  • Galaxy S4 Play Store Edition (4.4.2) normal
    • maxMemory: 201326592
    • getMemoryClass: 192
  • Galaxy S4 Play Store Edition (4.4.2) large heap
    • maxmemory: 536870912
    • getMemoryClass: 192

Inne Urządzenia

  • Huawei Nexus 6P (6.0.1) normal
    • maxMemory: 201326592
    • getMemoryClass: 192

Nie testowałem tych dwóch metod przy użyciu specjalnej opcji manifestu android:largeHeap="true" dostępnej od Honeycomb, ale dzięki cmcromance i tencent mamy kilka przykładowych wartości largeHeap, jak opisano powyżej.

Moje oczekiwanie (które wydaje się być wspierane przez duże liczby powyżej) byłoby takie, że ta opcja będzie miała efekt podobny do Ustawienia sterta ręcznie przez rooted OS - to znaczy, że podniesie wartość {[2] } pozostawiając getMemoryClass() Sam. Istnieje inna metoda, getLargeMemoryClass(), która wskazuje, ile pamięci jest dozwolone dla aplikacji używającej ustawienia largeHeap. Dokumentacja getLargeMemoryClass() stwierdza: "większość aplikacji nie powinna potrzebować takiej ilości pamięci i powinna pozostać z limitem getMemoryClass ()."

Jeśli dobrze zgadłem, to użycie tej opcji przyniosłoby te same korzyści (i zagrożenia) podobnie jak korzystanie z przestrzeni udostępnionej przez użytkownika, który podniósł stertę za pośrednictwem zakorzenionego systemu operacyjnego (tj. jeśli aplikacja używa dodatkowej pamięci, prawdopodobnie nie będzie grać tak ładnie z innymi aplikacjami, które użytkownik uruchamia w tym samym czasie).

Zauważ, że klasa pamięci najwyraźniej nie musi być wielokrotnością 8MB.

Z powyższego widać, że wynik {[4] } jest niezmienny dla danej konfiguracji urządzenia / systemu operacyjnego, podczas gdy wartość maxMemory () zmienia się, gdy sterta jest ustawiona inaczej przez użytkownika.

Moje własne doświadczenie praktyczne jest takie, że na G1 (który ma klasę pamięci 16), jeśli ręcznie wybieram 24MB jako rozmiar sterty, mogę uruchomić bez błędów, nawet gdy moje zużycie pamięci może dryfować w kierunku 20MB(prawdopodobnie może wzrosnąć do 24MB, chociaż nie próbowałem tego). Ale inne podobnie duże aplikacje mogą zostać wypłukane z pamięci w wyniku pigginess mojej własnej aplikacji. I odwrotnie, moja Aplikacja może zostać spłukana z pamięci, jeśli te inne aplikacje wymagające dużej konserwacji są przenoszone na pierwszy plan przez użytkownika.

Nie można więc przekroczyć ilości pamięci określonej przez maxMemory(). I powinieneś spróbować utrzymać się w granicach określonych przez getMemoryClass(). Jednym ze sposobów, aby to zrobić, jeśli Wszystko inne zawiedzie, może być ograniczenie funkcjonalności takich urządzeń w sposób, który oszczędza pamięć.

Wreszcie, jeśli planujesz przejść przez liczbę megabajtów określonych w getMemoryClass(), moja rada będzie pracować długo i ciężko na zapisywanie i przywracanie stanu aplikacji, dzięki czemu wrażenia użytkownika są praktycznie niezakłócone, Jeśli onStop() / onResume() następuje cykl.

W moim przypadku, ze względu na wydajność ograniczam moją aplikację do urządzeń z systemem 2.2 i nowszym, a to oznacza, że prawie wszystkie urządzenia z moją aplikacją będą miały memoryClass 24 lub wyższy. Mogę więc zaprojektować, aby zajmował do 20 MB sterty i czuję się całkiem pewny, że moja aplikacja będzie dobrze grać z innymi aplikacjami, które użytkownik może uruchomić w tym samym czas.

Ale zawsze będzie kilku zakorzenionych użytkowników, którzy załadowali wersję Androida 2.2 lub nowszą na starsze urządzenie(np. Gdy napotkasz taką konfigurację, najlepiej, powinieneś zmniejszyć zużycie pamięci, nawet jeśli maxMemory() mówi ci, że możesz przejść znacznie wyżej niż 16MB, które getMemoryClass() mówi ci, że powinieneś być celem. A jeśli nie możesz niezawodnie zapewnić, że Twoja aplikacja będzie żyć w tym budżecie, to przynajmniej upewnij się, że onStop() / Działa bezproblemowo.

getMemoryClass(), jak wskazała Diane Hackborn (hackbod) powyżej, jest dostępny tylko z powrotem do poziomu API 5 (Android 2.0), a więc, jak radzi, można założyć, że fizyczny sprzęt dowolnego urządzenia z wcześniejszą wersją systemu operacyjnego jest zaprojektowany tak, aby optymalnie obsługiwać Aplikacje zajmujące przestrzeń sterty nie więcej niż 16MB.

Natomiast, maxMemory(), zgodnie z dokumentacją, jest dostępny aż do poziomu API 1. maxMemory(), w wersji pre-2.0, będzie prawdopodobnie Zwraca wartość 16MB, ale ja czy widzę, że w moich (znacznie późniejszych) wersjach CyanogenMod użytkownik może wybrać wartość sterty tak niską, jak 12MB, co prawdopodobnie skutkowałoby niższym limitem sterty, więc sugerowałbym, abyś kontynuował testowanie wartości maxMemory(), nawet dla wersji systemu operacyjnego przed 2.0. Możesz nawet odmówić uruchomienia w mało prawdopodobnym przypadku, gdy ta wartość jest ustawiona nawet poniżej 16MB, jeśli musisz mieć więcej niż maxMemory() wskazuje jest dozwolone.

 423
Author: Carl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-12 03:46:20

Oficjalny API to:

To zostało wprowadzone w 2.0, gdzie pojawiły się większe urządzenia pamięci. Można założyć, że urządzenia z wcześniejszymi wersjami systemu operacyjnego używają oryginalnej klasy pamięci (16).

 20
Author: hackbod,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-21 02:30:41

Debug.getNativeHeapSize() myślę,że da radę. Jest tam od 1.0.

Klasa Debug ma wiele świetnych metod śledzenia alokacji i innych problemów z wydajnością. Ponadto, jeśli chcesz wykryć sytuację o niskiej pamięci, Sprawdź Activity.onLowMemory().

 13
Author: Neil Traft,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-04-13 22:18:22

Oto Jak to zrobić:

Uzyskanie maksymalnego rozmiaru stosu, z którego może korzystać aplikacja:

Runtime runtime = Runtime.getRuntime();
long maxMemory=runtime.maxMemory();

Uzyskiwanie ilości sterty, z której obecnie korzysta Twoja aplikacja:

long usedMemory=runtime.totalMemory() - runtime.freeMemory();

Określenie, ile sterty może teraz wykorzystać Twoja aplikacja (dostępna pamięć):

long availableMemory=maxMemory-usedMemory;

I, aby ładnie sformatować każdy z nich, możesz użyć:

String formattedMemorySize=Formatter.formatShortFileSize(context,memorySize); 
 8
Author: android developer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-14 06:17:28

Zwraca maksymalny rozmiar sterty w bajtach:

Runtime.getRuntime().maxMemory()

Używałem ActivityManager.getMemoryClass() ale na CyanogenMod 7 (nie testowałem go gdzie indziej) zwraca błędną wartość, jeśli użytkownik ustawia rozmiar sterty ręcznie.

 4
Author: fhucho,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-24 10:31:18

Asus Nexus 7 (2013) 32Gig: getMemoryClass()=192 maxMemory ()=201326592

Popełniłem błąd prototypując moją grę na Nexusie 7, a potem odkryłem, że prawie natychmiast wyczerpała się pamięć na tablecie mojej żony 4.04 (memoryclass 48, maxmemory 50331648)

Będę musiał zrestrukturyzować mój projekt, aby załadować mniej zasobów, gdy stwierdzę, że memoryclass jest niski.
Czy istnieje sposób w Javie, aby zobaczyć bieżący rozmiar sterty? (Widzę to wyraźnie w logCat podczas debugowania, ale chciałbym zobaczyć to w kodzie do adaptacji, jak gdyby currentheap>(maxmemory/2) unload high quality bitmaps load low quality

 1
Author: Tkraindesigns,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-03 04:12:27

Niektóre operacje są szybsze niż java heap space manager. opóźnianie operacji przez jakiś czas może zwolnić miejsce w pamięci. Możesz użyć tej metody, aby uniknąć błędu rozmiaru sterty:

waitForGarbageCollector(new Runnable() {
  @Override
  public void run() {

    // Your operations.
  }
});

/**
 * Measure used memory and give garbage collector time to free up some
 * space.
 *
 * @param callback Callback operations to be done when memory is free.
 */
public static void waitForGarbageCollector(final Runnable callback) {

  Runtime runtime;
  long maxMemory;
  long usedMemory;
  double availableMemoryPercentage = 1.0;
  final double MIN_AVAILABLE_MEMORY_PERCENTAGE = 0.1;
  final int DELAY_TIME = 5 * 1000;

  runtime =
    Runtime.getRuntime();

  maxMemory =
    runtime.maxMemory();

  usedMemory =
    runtime.totalMemory() -
    runtime.freeMemory();

  availableMemoryPercentage =
    1 -
    (double) usedMemory /
    maxMemory;

  if (availableMemoryPercentage < MIN_AVAILABLE_MEMORY_PERCENTAGE) {

    try {
      Thread.sleep(DELAY_TIME);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }

    waitForGarbageCollector(
      callback);
  } else {

    // Memory resources are availavle, go to next operation:

    callback.run();
  }
}
 1
Author: Zon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-14 06:04:32

Masz na myśli programowo, czy tylko podczas tworzenia i debugowania? Jeśli to drugie, możesz zobaczyć te informacje z perspektywy DDMS w Eclipse. Gdy emulator (być może nawet fizyczny telefon, który jest podłączony) jest uruchomiony, wyświetli listę aktywnych procesów w oknie po lewej stronie. Możesz go wybrać i istnieje opcja śledzenia alokacji sterty.

 0
Author: Steve Haley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-04-13 16:00:41
Runtime rt = Runtime.getRuntime();
rt.maxMemory()

Wartość to b

ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
am.getMemoryClass()

Wartość to MB

 0
Author: qinqie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-10 08:19:28