Maksymalny budżet pamięci aplikacji ios

152

Pracuję nad grą na iOS, która ma na celu co najmniej 3gs. Używamy zasobów HD dla urządzeń wyświetlających Retina (iPhone 4, iPod touch 4 generacji).

Jeśli chodzi o pamięć, Ipod Touch 4.generacji wydaje się być dla nas najbardziej ograniczającym urządzeniem, ponieważ ma taką samą ilość pamięci RAM (256 w porównaniu do 512 w Iphone 4) co 3Gs, ale używamy na nim zasobów HD. Aplikacja ulegała awarii podczas próby załadowania 100-110 MB pamięci RAM, ale teraz, gdy spadliśmy do 70 MB, nigdy nie mieliśmy awarii ładowania.

Po wielu poszukiwaniach wydaje się, że nie ma oficjalnego twardego limitu, więc jak powinniśmy wiedzieć, jakiego budżetu pamięci użyć, aby był bezpieczny? Chcemy dać artystom budżet, z którego mogą korzystać, bez obaw o pamięć dla każdej mapy.

frilla
źródło
14
Nie jestem pewien, jak to pytanie może być duplikatem czegoś, co zostało zadane w późniejszym czasie.
Jasper,

Odpowiedzi:

42

Myślę, że odpowiedziałeś na własne pytanie: staraj się nie przekraczać limitu 70 Mb, jednak tak naprawdę zależy to od wielu rzeczy: jakiej wersji iOS używasz (nie SDK), ile aplikacji działa w tle, jakiej dokładnie pamięci używasz itp.

Po prostu unikaj natychmiastowych rozprysków pamięci (np. Używasz 40 MB pamięci RAM, a następnie przydzielasz 80 MB więcej na krótkie obliczenia). W takim przypadku iOS natychmiast zabiłby twoją aplikację.

Powinieneś również rozważyć leniwe ładowanie zasobów (ładuj je tylko wtedy, gdy naprawdę potrzebujesz, a nie wcześniej).

Maks
źródło
2
Po prostu chcieliśmy umieścić jak najwięcej rzeczy (grafiki i dźwięków). Artyści zawsze będą chcieli włożyć w grę jak najwięcej, dlatego chcę ograniczyć ich budżet. Myślę, że będziemy musieli po prostu przetestować na wielu różnych urządzeniach w różnych ustawieniach, aby znaleźć rozsądny maksymalny rozmiar pamięci do wykorzystania.
frilla
2
Czy przydzielenie tylko 70 MB (co prawdopodobnie jest poniżej budżetu) w dowolnym momencie na tym urządzeniu (nawet po intensywnym użyciu w innych aplikacjach wymagających dużej pamięci) zawsze zagwarantuje pomyślną alokację, czy może nadal ulegnie awarii?
Steven Lu
1
@Steven Lu to zależy od twojego urządzenia. Np. Na nowszych, jak iPhone5 czy iPad4, przydział 70 Mb nie stanowi żadnego problemu.
Maksymalnie
1
tak, ale chcę wiedzieć, czy mogę być pewien, że dopóki utrzymam całkowite wykorzystanie mojej aplikacji w ramach budżetu pamięci określonego urządzenia magicznego, nie zostanie ona zakończona!
Steven Lu
1
nie ma żadnych gwarancji
Max
421

Wyniki testów za pomocą narzędzia Split napisał (link w jego odpowiedzi):

urządzenie: (kwota awarii / całkowita kwota / procent całości)

  • iPad1: 127 MB / 256 MB / 49%
  • iPad2: 275 MB / 512 MB / 53%
  • iPad3: 645 MB / 1024 MB / 62%
  • iPad4: 585 MB / 1024 MB / 57% (iOS 8.1)
  • iPad Mini 1.generacji: 297 MB / 512 MB / 58%
  • iPad Mini Retina: 696 MB / 1024 MB / 68% (iOS 7.1)
  • iPad Air: 697 MB / 1024 MB / 68%
  • iPad Air 2: 1383 MB / 2048 MB / 68% (iOS 10.2.1)
  • iPad Pro 9,7 cala: 1395 MB / 1971 MB / 71% (iOS 10.0.2 (14A456))
  • iPad Pro 10,5 cala: 3057/4000/76% (iOS 11 beta4)
  • iPad Pro 12,9 cala (2015): 3058/3999/76% (iOS 11.2.1)
  • iPad Pro 12,9 cala (2017): 3057/3974/77% (iOS 11 beta4)
  • iPad Pro 11,0 ”(2018): 2858/3769/76% (iOS 12.1)
  • iPad Pro 12,9 cala (2018, 1 TB): 4598/5650/81% (iOS 12.1)
  • iPad 10.2: 1844/2998/62% (iOS 13.2.3)
  • iPod touch 4. generacji: 130 MB / 256 MB / 51% (iOS 6.1.1)
  • iPod touch piątej generacji: 286 MB / 512 MB / 56% (iOS 7.0)
  • iPhone4: 325 MB / 512 MB / 63%
  • iPhone4s: 286 MB / 512 MB / 56%
  • iPhone5: 645 MB / 1024 MB / 62%
  • iPhone5s: 646 MB / 1024 MB / 63%
  • iPhone6: 645 MB / 1024 MB / 62% (iOS 8.x)
  • iPhone6 ​​+: 645 MB / 1024 MB / 62% (iOS 8.x)
  • iPhone6s: 1396 MB / 2048 MB / 68% (iOS 9.2)
  • iPhone6s +: 1392 MB / 2048 MB / 68% (iOS 10.2.1)
  • iPhoneSE: 1395 MB / 2048 MB / 69% (iOS 9.3)
  • iPhone7: 1395/2048 MB / 68% (iOS 10.2)
  • iPhone7 +: 2040 MB / 3072 MB / 66% (iOS 10.2.1)
  • iPhone8: 1364/1990 MB / 70% (iOS 12.1)
  • iPhone X: 1392/2785/50% (iOS 11.2.1)
  • iPhone XS: 2040/3754/54% (iOS 12.1)
  • iPhone XS Max: 2039/3735/55% (iOS 12.1)
  • iPhone XR: 1792/2813/63% (iOS 12.1)
  • iPhone 11: 2068/3844/54% (iOS 13.1.3)
  • iPhone 11 Pro Max: 2067/3740/55% (iOS 13.2.3)
Jaspis
źródło
2
iPhone4: podobna wartość potwierdzona, wydaje się
legalna
3
iPhone 5 zawiesza się przy ± 645 MB.
asp_net
4
@JasperPol Zredagowałem Twój post, aby uwzględnić różne urządzenia, które posiadam, mam nadzieję, że wszystko w porządku. Dodałem wersję iOS, na której testowałem, na wypadek, gdyby miała znaczenie, ale możesz ją usunąć, jeśli uważasz, że nie jest to ważne.
JosephH
2
Wspaniale, że ta lista została utworzona i utrzymywana. Z mojego doświadczenia wynika, że ​​musiałem utrzymywać pamięć znacznie gorszą, aby być bezpiecznym, może 20% tego, co tutaj pokazano. Różnice między urządzeniami są również bardzo zmienne.
user1021430
1
Właśnie uruchomiłem to na iPadzie Pro 12,9. Ostrzeżenie dotyczące pamięci przy 2451 MB, awaria przy 3064 MB, łącznie 3981 MB.
zablokuj
134

Stworzyłem małe narzędzie, które próbuje przydzielić jak najwięcej pamięci do awarii i rejestruje, kiedy wystąpiły ostrzeżenia pamięci i awaria. Pomaga to dowiedzieć się, jaki jest budżet pamięci dla dowolnego urządzenia z systemem iOS.

https://github.com/Split82/iOSMemoryBudgetTest

Rozdzielać
źródło
Zrobiłem interesujący test: uruchomiłem aplikację z wykorzystaniem pamięci monitorującej xcode, wszedłem w tło, uruchomiłem Test budżetu. Test został zakończony, podczas gdy moja aplikacja działająca w tle nie. Chcę wiedzieć, dlaczego. Jest to również sprzeczne z tym, co @cprcrack powiedział w drugiej odpowiedzi.
Roberto
19

W mojej aplikacji wrażenia użytkownika są lepsze, jeśli używane jest więcej pamięci, więc muszę zdecydować, czy naprawdę powinienem zwolnić całą dostępną pamięć didReceiveMemoryWarning. W oparciu o odpowiedź Splitu i Jaspera Pol, użycie maksymalnie 45% całkowitej pamięci urządzenia wydaje się być bezpiecznym progiem (dzięki chłopaki).

Gdyby ktoś chciał spojrzeć na moją rzeczywistą realizację:

#import "mach/mach.h"

- (void)didReceiveMemoryWarning
{
    // Remember to call super
    [super didReceiveMemoryWarning];

    // If we are using more than 45% of the memory, free even important resources,
    // because the app might be killed by the OS if we don't
    if ([self __getMemoryUsedPer1] > 0.45)
    {
        // Free important resources here
    }

    // Free regular unimportant resources always here
}

- (float)__getMemoryUsedPer1
{
    struct mach_task_basic_info info;
    mach_msg_type_number_t size = sizeof(info);
    kern_return_t kerr = task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&info, &size);
    if (kerr == KERN_SUCCESS)
    {
        float used_bytes = info.resident_size;
        float total_bytes = [NSProcessInfo processInfo].physicalMemory;
        //NSLog(@"Used: %f MB out of %f MB (%f%%)", used_bytes / 1024.0f / 1024.0f, total_bytes / 1024.0f / 1024.0f, used_bytes * 100.0f / total_bytes);
        return used_bytes / total_bytes;
    }
    return 1;
}

Swift (na podstawie tej odpowiedzi ):

func __getMemoryUsedPer1() -> Float
{
    let MACH_TASK_BASIC_INFO_COUNT = (sizeof(mach_task_basic_info_data_t) / sizeof(natural_t))
    let name = mach_task_self_
    let flavor = task_flavor_t(MACH_TASK_BASIC_INFO)
    var size = mach_msg_type_number_t(MACH_TASK_BASIC_INFO_COUNT)
    var infoPointer = UnsafeMutablePointer<mach_task_basic_info>.alloc(1)
    let kerr = task_info(name, flavor, UnsafeMutablePointer(infoPointer), &size)
    let info = infoPointer.move()
    infoPointer.dealloc(1)
    if kerr == KERN_SUCCESS
    {
        var used_bytes: Float = Float(info.resident_size)
        var total_bytes: Float = Float(NSProcessInfo.processInfo().physicalMemory)
        println("Used: \(used_bytes / 1024.0 / 1024.0) MB out of \(total_bytes / 1024.0 / 1024.0) MB (\(used_bytes * 100.0 / total_bytes)%%)")
        return used_bytes / total_bytes
    }
    return 1
}
cprcrack
źródło
1
rozmiar powinien wynosić TASK_BASIC_INFO_COUNT zamiast sizeof (info) - ten błąd został skopiowany i wklejony w wiele miejsc z tym samym kodem
Maxim Kholyavkin
Dzięki Speakus. Wydaje się, że masz rację na podstawie tego linku . Czy masz jakieś inne odniesienie, w którym można znaleźć te informacje?
cprcrack
Apple używa również
Maxim Kholyavkin,
45% nie jest już bezpiecznym limitem, jest zbyt blisko 50% wartości awarii dla iPhone'a X. Proponuję użyć 40% lub osobną wartość dla każdego urządzenia.
Slyv
8

Tworząc repozytorium SPLITS, zbudowałem je, aby przetestować pamięć iOS, którą można przydzielić do dzisiejszego rozszerzenia

iOSMemoryBudgetTestForExtension

Oto wynik, który otrzymałem w telefonie iPhone 5s

Ostrzeżenie dotyczące pamięci przy 10 MB

Awaria aplikacji przy 12 MB

W ten sposób Apple po prostu zezwala, aby wszelkie rozszerzenia działały z pełnym potencjałem .

Szorstki
źródło
7

Powinieneś obejrzeć sesję 147 z filmów z sesji WWDC 2010 . Jest to „Zaawansowana optymalizacja wydajności w systemie iPhone OS, część 2”.
Istnieje wiele dobrych rad dotyczących optymalizacji pamięci.

Oto kilka wskazówek:

  • Użyj zagnieżdżonych NSAutoReleasePools, aby upewnić się, że użycie pamięci nie gwałtownie wzrośnie.
  • Użyj CGImageSourcepodczas tworzenia miniatur z dużych obrazów.
  • Reaguj na ostrzeżenia o małej ilości pamięci.
Kobski
źródło
Moje pytanie nie dotyczy tego, jak optymalizować (dzięki za link), ale ile możemy sobie pozwolić na użycie. Powodem jest to, że jeśli na przykład zoptymalizujemy, aby uzyskać 20 MB, to artyści będą chcieli wykorzystać te 20 MB, jeśli mieści się w rozsądnym „budżecie”, czyli mając pewność, że nie spowoduje to żadnych problemów z wydajnością ani awarii pamięci.
frilla
DOBRZE. Awaria nastąpi, ponieważ system operacyjny zamyka aplikację z powodu ograniczonej pamięci. Możesz po prostu dodać NSLogwnętrze, didReceiveMemoryWarninga następnie przeprowadzić testy, w których przydzielisz różne ilości pamięci, a następnie zobacz, kiedy zaczną
pojawiać się
4

Począwszy od iOS13, istnieje obsługiwany przez Apple sposób wykonywania zapytań przy użyciu

#include <os/proc.h>

size_t os_proc_available_memory(void)

Wprowadzono tutaj: https://developer.apple.com/videos/play/wwdc2019/606/

Około min 29 lat.

Edycja: dodanie linku do dokumentacji https://developer.apple.com/documentation/os/3191911-os_proc_available_memory?language=objc

Exaberri Tokugawa
źródło
Wreszcie! Przetestowałem os_proc_available_memory () na kilku urządzeniach i wyniki są bardzo podobne do wartości w dużej tabeli powyżej!
Slyv
3
- (float)__getMemoryUsedPer1
{
    struct mach_task_basic_info info;
    mach_msg_type_number_t size = MACH_TASK_BASIC_INFO;
    kern_return_t kerr = task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&info, &size);
    if (kerr == KERN_SUCCESS)
    {
        float used_bytes = info.resident_size;
        float total_bytes = [NSProcessInfo processInfo].physicalMemory;
        //NSLog(@"Used: %f MB out of %f MB (%f%%)", used_bytes / 1024.0f / 1024.0f, total_bytes / 1024.0f / 1024.0f, used_bytes * 100.0f / total_bytes);
        return used_bytes / total_bytes;
    }
    return 1;
}

Jeśli użyje się TASK_BASIC_INFO_COUNT zamiast MACH_TASK_BASIC_INFO, otrzymasz

kerr == KERN_INVALID_ARGUMENT (4)

Dmitry Preobrazhenskiy
źródło
Powinieneś przynajmniej wspomnieć, że twoja odpowiedź jest prawie dokładną kopiowaniem i wklejaniem powyższego @ cprcrack . Jedyna różnica to TASK_BASIC_INFO_COUNT.
mrvincenzo
2

Stworzyłem jeszcze jedną listę, sortując listę Jaspers według pamięci RAM urządzenia (zrobiłem własne testy za pomocą narzędzia Split i poprawiłem niektóre wyniki - sprawdź moje komentarze w wątku Jaspers).

pamięć RAM urządzenia: procentowy zakres awarii

  • 256 MB: 49% - 51%
  • 512 MB: 53% - 63%
  • 1024 MB: 57% - 68%
  • 2048 MB: 68% - 69%
  • 3072 MB: 63% - 66%
  • 4096 MB: 77%
  • 6144 MB: 81%

Przypadki specjalne:

  • iPhone X (3072 MB): 50%
  • iPhone XS / XS Max (4096 MB): 55%
  • iPhone XR (3072 MB): 63%
  • iPhone 11/11 Pro Max (4096 MB): 54% - 55%

Pamięć RAM urządzenia można łatwo odczytać:

[NSProcessInfo processInfo].physicalMemory

Z mojego doświadczenia wynika, że ​​można bezpiecznie używać 45% dla urządzeń 1 GB, 50% dla urządzeń 2/3 GB i 55% dla urządzeń 4 GB. Procent dla macOS może być nieco większy.

Slyv
źródło
aktualizacja: Wygląda na to, że iPhone X jest wyjątkiem - ulega awarii, gdy używane jest 50% pamięci RAM (testowane z aplikacją iOSMemoryBudgetTest). Zaktualizowałem listę.
Slyv
0

Pracując z wieloma powyższymi odpowiedziami, zaimplementowałem nową metodę Apples os_proc_available_memory()dla iOS 13+, w połączeniu z NSByteCountFormatterktórą oferuje szereg przydatnych opcji formatowania dla ładniejszego wyjścia pamięci:

#include <os/proc.h>

....

- (NSString *)memoryStringForBytes:(unsigned long long)memoryBytes {
    NSByteCountFormatter *byteFormatter = [[NSByteCountFormatter alloc] init];
    byteFormatter.allowedUnits = NSByteCountFormatterUseGB;
    byteFormatter.countStyle = NSByteCountFormatterCountStyleMemory;
    NSString *memoryString = [byteFormatter stringFromByteCount:memoryBytes];
    return memoryString;
}

- (void)memoryLoggingOutput {
    if (@available(iOS 13.0, *)) {
        NSLog(@"Physical memory available: %@", [self memoryStringForBytes:[NSProcessInfo processInfo].physicalMemory]);
        NSLog(@"Memory A (brackets): %@", [self memoryStringForBytes:(long)os_proc_available_memory()]);
        NSLog(@"Memory B (no brackets): %@", [self memoryStringForBytes:(long)os_proc_available_memory]);
    }
}

Ważna uwaga: nie zapomnij ()o końcu. W metodzie zawarłem obie NSLogopcje, memoryLoggingOutputponieważ nie ostrzega, że ​​ich brakuje, a brak nawiasów zwraca nieoczekiwany, ale stały wynik.

Ciąg zwrócony z metody memoryStringForByteszwraca wartości, takie jak:

NSLog(@"%@", [self memoryStringForBytes:(long)os_proc_available_memory()]); // 1.93 GB
// 2 seconds later
NSLog(@"%@", [self memoryStringForBytes:(long)os_proc_available_memory()]); // 1.84 GB
App Dev Guy
źródło