Szybkie Zarządzanie Pamięcią

To pytanie zostało wyczyszczone, a ważne informacje przeniesione do Odpowiedzi poniżej.


Mam kilka pytań na temat zarządzania pamięcią.

Buduję aplikację do edycji zdjęć. Dlatego ważne jest niskie zużycie pamięci. Również nie będę Kod Pocztowy, ponieważ nie mam dużego wycieku pamięci podczas robienia jednej konkretnej rzeczy. Po prostu tracę kilka KB/MB przy wszystkim, co się dzieje. A przechodzenie przez dziesiątki tysięcy linii kodu, aby znaleźć kilobajty, nie jest zabawne ;)

Moja aplikacja wykorzystuje podstawowe dane, wiele rzeczy cifilter, lokalizację i podstawy.

Mój pierwszy Widok to tylko widok tableview, który kosztuje mnie około 5MB pamięci. Następnie robisz zdjęcia, stosujesz filtry, to zostaje zapisane w podstawowych danych, a następnie wracasz do pierwszego widoku.

Czy można naprawdę pozbyć się wszystkiego w pamięci z wyjątkiem danych potrzebnych do napędu tego pierwszego widoku. (to bardzo save i zajebiste 5mb)

Czy zawsze będzie coś zostawiony, nawet jeśli ustawisz wszystko na zero?


Pytanie Bonusowe: czy istnieje różnica w rozmiarze pliku / obciążeniu procesora między UIImageJPEGRepresentation i UIImagePNGRepresentation? Wiem, że można ustawić jakość kompresji metodą JPEG (trudniej na cpu/gpu?).

Staram się zmniejszyć ciśnienie pamięci za wszelką cenę.

Update:

Zwrócono mi uwagę, że pytanie może być zbyt niejasne.

Problemy, które miałem w pewnym momencie lub innym były następujące:

    W niektórych momentach szczytowe zużycie pamięci jest zbyt wysokie.]} [[36]} przejście do drugiego kontrolera viewcontrollera i z powrotem powoduje wyciek
  • Edycja obrazu powoduje wyciek pamięci.
  • zastosowanie filtra do więcej niż 4-5 obrazów powoduje awarię z powodu niskiej pamięci, nie było więcej wycieków pamięci w tym momencie. (zweryfikowane w instrumentach)

P. S to wszystko było testowane na iPhonie 4s, a nie na symulatorze.

był tu mem aby nieco rozjaśnić nastrój na tej stronie.

Author: R Menke, 2015-01-15

2 answers

To pytanie było otwarte wystarczająco długo i teraz czuję się wystarczająco pewny siebie, aby odpowiedzieć.


Różne poziomy MM:

Pamięć Sprzętowa

W języku Swift z ARC nie mamy możliwości wyczyszczenia faktycznej pamięci RAM. Możemy tylko sprawić, że system operacyjny zrobi to za nas. Jedna część to użycie odpowiedniego kodu (optionals i weak), Druga część to tworzenie czasu dla systemu operacyjnego, aby wykonać swoje zadanie.

Wyobraźmy sobie, że mamy funkcję to działa na wszystkich wątkach w nieskończoność. Robi jedną rzecz, ładuje obraz, konwertuje na czarno / biały i zapisuje. Wszystkie obrazy mają maksymalnie kilka mb, a funkcja nie powoduje wycieków pamięci Programowej. Ponieważ obrazy nie mają ustawionego rozmiaru i mogą mieć inną kompresję, nie mają tego samego śladu. Ta funkcja zawsze spowoduje awarię aplikacji.

Ten "sprzętowy" wyciek pamięci jest spowodowany przez funkcję zawsze zajmującą następny dostępny slot pamięci.

System operacyjny nie wchodzi aby "wyczyścić pamięć", ponieważ nie ma czasu bezczynności. Umieszczenie opóźnienia między każdym przejściem całkowicie to naprawia.


Język specyficzny MM

Casting

Niektóre operacje nie mają wpływu na pamięć, inne tak:

let myInt : Int = 1
Float(myInt) // this creates a new instance

Spróbuj zamiast tego:

(myInt as Float) // this will not create a new instance.

Typy referencyjne vs typy wartości / klasy vs struktury

Obie mają swoje zalety i swoje niebezpieczeństwa.

Struktury są pamięciowe, ponieważ są typami wartości . Oznacza to, że kopiują ich wartości, gdy są przypisane do innej instancji, skutecznie podwajając zużycie pamięci. Nie ma rozwiązania / obejścia dla tego. To jest to, co tworzy Structs Structs.

Klasy nie mają takiego zachowania, ponieważ są typami referencyjnymi . Nie kopiują, gdy są przypisane. Zamiast tego tworzą kolejne odniesienie do ten sam obiekt . ARC lub automatyczne liczenie odniesień jest tym, co śledzi te odniesienia. Każdy obiekt posiada licznik odniesienia. Za każdym razem, gdy go przypisujesz, wzrasta o jeden. Za każdym razem, gdy ustawisz odniesienie do nil, funkcja zamykająca kończy się lub obiekt zamykający deinits, licznik spada.

Gdy licznik trafi 0, obiekt jest deinicjalizowany.

Istnieje sposób, aby zapobiec deinicjalizacji instancji, a tym samym stworzeniu przecieku. Jest to tzw. silny cykl odniesienia .

Dobre wyjaśnienie słabych

class MyClass {

    var otherClass : MyOtherClass?

    deinit {
        print("deinit") // never gets called
    }
}

class MyOtherClass {

    var myclass : MyClass?

    deinit {
        print("deinit") // never gets called
    }
}

var classA : MyClass? = MyClass()

// sorry about the force unwrapping, don't do it like this
classA!.otherClass = MyOtherClass()
classA!.otherClass!.myclass = classA // this looks silly but in some form this happens a lot

classA = nil
// neither the MyClass nor the MyOtherClass deinitialised and we no longer have a reference we can acces. Immortalitiy reached they have.

Set one reference to weak

class MyOtherClass {

    weak var myclass : MyClass?

    deinit {
        print("deinit") // gets called
    }
}

Inout

Funkcje przechwytują przekazywane im wartości. Ale można również oznaczyć te wartości jako inout. Pozwala to na zmianę struktury przekazanej do funkcji bez kopiowania struktury. Może to zaoszczędzić pamięć, w zależności od tego, co przekazujesz i co robisz w funkcji.

Jest również dobry sposób na wielokrotne zwracanie wartości bez użycia krotek.

var myInt : Int = 0

// return with inout
func inoutTest(inout number: Int) {

    number += 5

}

inoutTest(&myInt)
print(myInt) // prints 5

// basic function with return creates a new instance which takes up it's own memory space
func addTest(number:Int) -> Int {

    return number + 5

}

Programowanie Funkcyjne

Stan jest wartością w czasie

Programowanie funkcyjne jest licznikiem programowania zorientowanego obiektowo. Programowanie funkcyjne wykorzystuje stan niezmienny.

Więcej o tym tutaj

Programowanie obiektowe wykorzystuje obiekty, które mają zmienne/mutujące Stany. Zamiast tworzyć nową wartość, stare wartości są aktualizacja.

Programowanie funkcyjne może zużywać więcej pamięci.

Przykład na FP


Optionals

Opcje pozwalają ustawić coś na zero. Spowoduje to zmniejszenie liczby klas referencyjnych lub deinicjalizację struktur. Ustawienie rzeczy na zero jest najprostszym sposobem czyszczenia pamięci. To idzie w parze z ARC. Po ustawieniu wszystkich referencji klasy na nil, spowoduje to wyłączenie i zwolnienie pamięci.

Jeśli nie stworzysz instancja jako opcja, dane pozostaną w pamięci do czasu zakończenia funkcji zamykającej lub zakończenia klasy zamykającej. Możesz nie wiedzieć, kiedy to się stanie. Opcje dają Ci kontrolę nad tym, co pozostanie przy życiu na jak długo.


API MM

Wiele "wycieków pamięci" jest powodowanych przez frameworki , które mają funkcję "clean up", której być może nie wywołałeś. Dobrym przykładem jest UIGraphicsEndImageContext() kontekst pozostanie w pamięci dopóki ta funkcja nie zostanie wywołana. Nie czyszczenie po zakończeniu funkcji, która utworzyła kontekst, lub gdy obraz jest ustawiony na zero.

Innym dobrym przykładem jest odrzucenie Viewcontrollerów. To może mieć sens, aby segue do jednego VC, a następnie segue z powrotem, ale segue faktycznie tworzy VC. Segue back nie niszczy VC. Wywołanie dismissViewControllerAnimated(), aby usunąć go z pamięci.

Przeczytaj Referencje klas i sprawdź, czy nie ma funkcji "clean up".


Jeśli potrzebujesz narzędzi, aby znaleźć przeciek, sprawdź druga odpowiedź na to pytanie.

 27
Author: R Menke,
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-04-12 07:31:24

Tutaj wpisz opis obrazka

Kliknij nazwę aplikacji w prawym górnym rogu Xcode.

Tutaj wpisz opis obrazka

Kliknij "Edytuj schemat" w menu, które się pojawi.

Tutaj wpisz opis obrazka

Upewnij się, że po lewej stronie jest zaznaczone "Uruchom", a następnie kliknij kartę diagnostyka w górnej części okna.

W nagłówku "zarządzanie pamięcią" zaznacz "Włącz ochronę Malloc"

Możesz również spróbować sprawdzić 'distributed objects 'i' malloc stack ' pod 'logging' header

Więcej informacji na temat guard malloc, guard edges i scribble można znaleźć tutaj .



mam nadzieję, że to pomoże!

 6
Author: DeveloperACE,
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-05-23 12:18:04