Zarządzanie pamięcią: ręczne czy automatyczne
Łukasz Kosson
Tomasz Wasersztrum
Podstawy
Podstawy
Stos i sterta
Podstawy
Stos i sterta
Podstawy
Stos i sterta malloc() i free()
Podstawy
Stos i sterta malloc() i free() (implementacja windows)
Podstawy
Stos i sterta malloc() i free() (implementacja windows)
tablica wolnych bloków
Podstawy
Stos i sterta malloc() i free() (implementacja windows)
tablica wolnych bloków bloki „zawieszone”
Podstawy
Stos i sterta malloc() i free() (implementacja windows)
tablica wolnych bloków bloki „zawieszone” schemat algorytmów
Podstawy
Stos i sterta malloc() i free() (implementacja windows)
tablica wolnych bloków bloki „zawieszone” schemat algorytmów
new i delete
Problemy zarządzania pamięcią
Problemy zarządzania pamięcią Wycieki pamięci (memory leak)
Problemy zarządzania pamięcią Wycieki pamięci (memory leak)
Pseudokod obsługi windy.
Problemy zarządzania pamięcią Wycieki pamięci (memory leak)
Pseudokod obsługi windy.
When a button is pressed: Get some memory, which will be used to remember the floor number Put the floor number into the memory Are we already on the target floor? If so, we have nothing to do: finished Otherwise: Wait until the lift is idle Go to the required floor Release the memory we used to remember the floor number
Problemy zarządzania pamięcią Wycieki pamięci (memory leak)
Problemy zarządzania pamięcią Wycieki pamięci (memory leak) Nieaktualne referencje (dangling pointers)
Problemy zarządzania pamięcią Wycieki pamięci (memory leak) Nieaktualne referencje (dangling pointers) Fragmentacja
Garbage collector
Garbage collector
Czym jest i co robi?
Garbage collector
Czym jest i co robi? Jeden z mechanizmów zarządzania zasobami (m.in. pamięcią)
Garbage collector
Czym jest i co robi? Jeden z mechanizmów zarządzania zasobami (m.in. pamięcią) Odpowiedzialny za zwalnianie niepotrzebnych zasobów
Garbage collector
Czym jest i co robi? Jeden z mechanizmów zarządzania zasobami (m.in. pamięcią) Odpowiedzialny za zwalnianie niepotrzebnych zasobów Często zmniejsza fragmentację (zewnętrzną i wewnętrzną) pamięci
Garbage collector
Czym nie jest i czego nie robi?
Garbage collector
Czym nie jest i czego nie robi? Nie zwalnia z racjonalnego korzystania z pamięci
Garbage collector
Czym nie jest i czego nie robi? Nie zwalnia z racjonalnego korzystania z pamięci Nie służy do wykrywania wycieków
Garbage collector
Czym nie jest i czego nie robi? Nie zwalnia z racjonalnego korzystania z pamięci Nie służy do wykrywania wycieków Nie dotyka zewnętrznych zasobów
Garbage collector
Czym nie jest i czego nie robi? Nie zwalnia z racjonalnego korzystania z pamięci Nie służy do wykrywania wycieków Nie dotyka zewnętrznych zasobów Nie czyni cudów
Garbage collector
Gdzie jest wykorzystywany?
Garbage collector
Gdzie jest wykorzystywany? Początki: LISP, 1960
Garbage collector
Gdzie jest wykorzystywany? Początki: LISP, 1960 Głównie wykorzystywany do zarządzania pamięcią operacyjną ...
Garbage collector
Gdzie jest wykorzystywany? Początki: LISP, 1960 Głównie wykorzystywany do zarządzania pamięcią operacyjną ... ... ale także np. połączeniami, plikami
Garbage collector
Gdzie jest wykorzystywany? Początki: LISP, 1960 Głównie wykorzystywany do zarządzania pamięcią operacyjną ... ... ale także np. połączeniami, plikami Środowiska, np: .NET, JVM (także ME)
Garbage collector
Gdzie jest wykorzystywany? Początki: LISP, 1960 Głównie wykorzystywany do zarządzania pamięcią operacyjną ... ... ale także np. połączeniami, plikami Środowiska, np: .NET, JVM (także ME) Języki skryptowe, np JavaScript
GC – zasada działania
Jakie obiekty sprzątać?
GC – zasada działania
Jakie obiekty sprzątać? Optymalne rozwiązanie: kasować obiekty nieosiągalne
semantycznie
GC – zasada działania
Jakie obiekty sprzątać? Optymalne rozwiązanie: kasować obiekty nieosiągalne
semantycznie Problem: zagadnienie równoważne problemowi stopu.
GC – zasada działania
Jakie obiekty sprzątać? Optymalne rozwiązanie: kasować obiekty nieosiągalne
semantycznie Problem: zagadnienie równoważne problemowi stopu. Prostsze rozwiązanie: osiągalność syntaktyczna
GC – zasada działania
Jakie obiekty sprzątać? Optymalne rozwiązanie: kasować obiekty nieosiągalne
semantycznie Problem: zagadnienie równoważne problemowi stopu. Prostsze rozwiązanie: osiągalność syntaktyczna Praktyka: rozwiązanie pośrednie
GC – zasada działania
Algorytm naiwny (mark and sweep):
GC – zasada działania
Algorytm naiwny (mark and sweep): Dla każdego obiektu trzymamy bit osiągalności
GC – zasada działania
Algorytm naiwny (mark and sweep): Dla każdego obiektu trzymamy bit osiągalności Zaczynając od obiektów bezpośrednio osiągalnych przeglądamy
strukturę obiektów
GC – zasada działania
Algorytm naiwny (mark and sweep): Dla każdego obiektu trzymamy bit osiągalności Zaczynając od obiektów bezpośrednio osiągalnych przeglądamy
strukturę obiektów Zwalniamy obiekty do których się nie udało dojść
GC – zasada działania
Wady algorytmu naiwnego:
GC – zasada działania
Wady algorytmu naiwnego: Wymaga wstrzymania procesu
GC – zasada działania
Wady algorytmu naiwnego: Wymaga wstrzymania procesu Przeglądanie całej pamięci
GC – zasada działania
Wady algorytmu naiwnego: Wymaga wstrzymania procesu Przeglądanie całej pamięci Duża fragmentacja pamięci
GC – zasada działania
Modyfikacje algorytmu mark-and-sweep:
GC – zasada działania
Modyfikacje algorytmu mark-and-sweep: Stop-and-copy: redukuje fragmentację, ale zwiększa dwukrotnie
wymagania pamięciowe
GC – zasada działania
Modyfikacje algorytmu mark-and-sweep: Stop-and-copy: redukuje fragmentację, ale zwiększa dwukrotnie
wymagania pamięciowe Mark-and-compact: redukuje fragmentację
GC – zasada działania
Obserwacja: Im obiekt młodszy, tym szybciej staje się niedostępny
GC – zasada działania
Obserwacja: Im obiekt młodszy, tym szybciej staje się niedostępny
Wniosek: Nie traktować wszystkich obiektów jednakowo
GC – zasada działania
Obserwacja: Im obiekt młodszy, tym szybciej staje się niedostępny
Wniosek: Nie traktować wszystkich obiektów jednakowo
Pomysł: Algorytmy pokoleniowe
GC – zasada działania
Obserwacja: Im obiekt młodszy, tym szybciej staje się niedostępny
Wniosek: Nie traktować wszystkich obiektów jednakowo
Pomysł: Algorytmy pokoleniowe
Efekt: Szybsze zwalnianie pamięci
GC – zasada działania
Współczesne GC: Rozróżnienie na obiekty młode i stare (dwie lub trzy klasy)
GC – zasada działania
Współczesne GC: Rozróżnienie na obiekty młode i stare (dwie lub trzy klasy)JVM: Obiekty młode odzyskiwane przez stop-and-copy Obiekty stare – przez mark-and-sweep
GC – zasada działania
Współczesne GC: Rozróżnienie na obiekty młode i stare (dwie lub trzy klasy)JVM: Obiekty młode odzyskiwane przez stop-and-copy Obiekty stare – przez mark-and-sweep Możliwość wymuszenia użycia innego algorytmu (w tym:
współbieżnego)
GC – zasada działania
Współczesne GC: Rozróżnienie na obiekty młode i stare (dwie lub trzy klasy)JVM: Obiekty młode odzyskiwane przez stop-and-copy Obiekty stare – przez mark-and-sweep Możliwość wymuszenia użycia innego algorytmu (w tym:
współbieżnego).NET: Wszystkie pokolenia obsługiwane przez mark-and-compact
GC – jak mu pomóc
GC – jak mu pomóc
Weak reference:
GC – jak mu pomóc
Weak reference: Działa jak zwykły wskaźnik ...
GC – jak mu pomóc
Weak reference: Działa jak zwykły wskaźnik ... ... ale nie jest traktowany przez GC jako referencja
GC – jak mu pomóc
Weak reference: Działa jak zwykły wskaźnik ... ... ale nie jest traktowany przez GC jako referencja Szczególnie przydatny przy implementowaniu pamięci podręcznej
GC – jak sobie pomóc
GC – jak sobie pomóc
Finalizacja:
GC – jak sobie pomóc
Finalizacja: Mechanizm zastępujący destruktory
GC – jak sobie pomóc
Finalizacja: Mechanizm zastępujący destruktory Kwestia wydajności
GC – jak sobie pomóc
Finalizacja: Mechanizm zastępujący destruktory Kwestia wydajności A co gdy korzystamy z zewnętrznych zasobów?
GC – środowiska hybrydowe
Co się dzieje w sytuacji, gdy mamy wskaźniki na obiekty?
GC – środowiska hybrydowe
Co się dzieje w sytuacji, gdy mamy wskaźniki na obiekty?unsafe{
Bitmap img = Image.FromFile(„pict.jpg”);BitmapData data = img.LockBits();byte* pixels = data.Scan0;Process(pixels);img.UnlockBits(data);
}
GC – środowiska hybrydowe
Co się dzieje w sytuacji, gdy mamy wskaźniki na obiekty?unsafe{
Bitmap img = Image.FromFile(„pict.jpg”);BitmapData data = img.LockBits();byte* pixels = data.Scan0;Process(pixels);img.UnlockBits(data);
} Odpowiedź:fixed (byte* pixels = data.Scan0){ ...}
Zamiast GC…
Zamiast GC… Zliczanie referencji
Zamiast GC…
refcountedstruct , REF() , UNREF()
Zliczanie referencji
struct refcountedstruct { int refcount;}
void REF(void *data){ struct refcountedstruct *rstruct; rstruct = (struct refcountedstruct *) data; rstruct->refcount++;}
Zamiast GC… Zliczanie referencji
void UNREF(void *data){ struct refcountedstruct *rstruct; rstruct = (struct refcountedstruct *) data; rstruct->refcount--; if(rstruct->refcount == 0) { free(rstruct); }}
refcountedstruct , REF() , UNREF()
Zamiast GC… Zliczanie referencji
struct mydata{ int refcount; int datafield;};void dosomething(struct mydata *data){
REF(data);/* Process data */UNREF(data);
}
refcountedstruct , REF() , UNREF() użycie w kodzie
Zamiast GC… Zliczanie referencji
Zamiast GC… Zliczanie referencji
Łatwe w obsłudze
Zamiast GC… Zliczanie referencji
Łatwe w obsłudze Proste w implementacji
Zamiast GC… Zliczanie referencji
Łatwe w obsłudze Proste w implementacji
Nie obsługuje poprawnie struktur cyklicznych
Zamiast GC… Zliczanie referencji
Łatwe w obsłudze Proste w implementacji
Nie obsługuje poprawnie struktur cyklicznych Spowalnia przypisania
Zamiast GC… Zliczanie referencji
Łatwe w obsłudze Proste w implementacji
Nie obsługuje poprawnie struktur cyklicznych Spowalnia przypisania Wymaga ciągłego pamiętania o REF i UNREF
Zamiast GC… Zliczanie referencji
Łatwe w obsłudze Proste w implementacji
Nie obsługuje poprawnie struktur cyklicznych Spowalnia przypisania Wymaga ciągłego pamiętania o REF i UNREF A jak REF albo UNREF rzuci wyjątek...
Zamiast GC… Zliczanie referencji
Zamiast GC… Zliczanie referencji Strefy pamięci (obstack)
Zamiast GC… Zliczanie referencji Strefy pamięci (obstack)
struct obstack *global_pool;struct obstack *connection_pool;struct obstack *request_pool;int main(){
/* inicjalizacja */while(1){
wait_for_connection();while(more_requests_available()){
handle_request();obstack_free(request_pool, NULL);
}obstack_free(connection_pool, NULL);
}}
Zamiast GC… Zliczanie referencji Strefy pamięci (obstack)
Zamiast GC… Zliczanie referencji Strefy pamięci (obstack)
Łatwe w obsłudze
Zamiast GC… Zliczanie referencji Strefy pamięci (obstack)
Łatwe w obsłudze Szereg dostępnych implementacji
Zamiast GC… Zliczanie referencji Strefy pamięci (obstack)
Łatwe w obsłudze Szereg dostępnych implementacji Szybkie
Zamiast GC… Zliczanie referencji Strefy pamięci (obstack)
Łatwe w obsłudze Szereg dostępnych implementacji Szybkie
Hermetyczne
Zamiast GC… Zliczanie referencji Strefy pamięci (obstack)
Łatwe w obsłudze Szereg dostępnych implementacji Szybkie
Hermetyczne Problem w przypadku zmian w kodzie
Zamiast GC… Zliczanie referencji Strefy pamięci (obstack)
Łatwe w obsłudze Szereg dostępnych implementacji Szybkie
Hermetyczne Problem w przypadku zmian w kodzie A jak pomylisz pulę pamięci przy alokacji...
Konfrontacja
Przykład 1 – wyrażeniaVector v1, v2, v3;Scalar s1, s2;
v3 = v1 * s1 + v2 * s2;
Konfrontacja
Przykład 1 – wyrażeniaVector v1, v2, v3;Scalar s1, s2;
v3 = v1 * s1 + v2 * s2;
Lub inaczej:v3 = v1.mult(s1).add(v2.mult(s2))
Konfrontacja
Przykład 1 – wyrażeniaVector v1, v2, v3;Scalar s1, s2;
v3 = v1 * s1 + v2 * s2;
Lub inaczej:v3 = v1.mult(s1).add(v2.mult(s2))
Ile obiektów będzie utworzonych?
Konfrontacja
Przykład 1 – wyrażeniaVector v1, v2, v3;Scalar s1, s2;
v3 = v1 * s1 + v2 * s2;
Lub inaczej:v3 = v1.mult(s1).add(v2.mult(s2))
Ile obiektów będzie utworzonych? Kto będzie sprzątał?
Konfrontacja
Przykład 2 – formatowanie
time_t tm;time(&tm);char *str = ctime(&tm);cout << str;delete str;
Kto sprząta?
Konfrontacja
Przykład 3 – zasoby zewnętrzne, GUI Problem: nie możemy samemu niszczyć obiektów Irytujący przykład: JFrame
JFrame frm = new JFrame();BigModel mdl = new BigModel();BigComponent cmp = new BigComponent(mdl);frm.add(cmp);frm.show();
Konfrontacja
Przykład 4 – wydajnośćclass A {
private int x; public A() { x = 0; ++x; }
}
class Example{
public static void Main() {
for (int i = 0; i < 500000000; ++i) { A a = new A(); }}
}
Konfrontacja
Wyniki dla linuxie (students)
Konfrontacja
Java:real 0m8.555suser 0m8.100ssys 0m0.350s
Konfrontacja
Java:real 0m8.555suser 0m8.100ssys 0m0.350s
Mono:real 0m2.907suser 0m2.690ssys 0m0.130s
Konfrontacja
Java:real 0m8.555suser 0m8.100ssys 0m0.350s
Mono:real 0m2.907suser 0m2.690ssys 0m0.130s
C++:real 0m5.320suser 0m4.360ssys 0m0.940s
Konfrontacja
A jak wyszło na Windows?
Konfrontacja
Java:Kernel: 0.015User: 0.156
.NET:Kernel: 0.031User: 0.109
C++:Kernel: 0.796User: 8.343
Konfrontacja
Przykład 5while (true){
Connection conn = GetConnection();ReadRequest(conn);SendResponse(conn);
}
Konfrontacja
Przykład 5while (true){
Connection conn = GetConnection();ReadRequest(conn);SendResponse(conn);
}
Pytanie: czy i kiedy połączenia same się będą zamykać?
Konfrontacja
Przykład 5while (true){
Connection conn = GetConnection();ReadRequest(conn);SendResponse(conn);
}
Pytanie: czy i kiedy połączenia same się będą zamykać? Odpowiedź: nie wiadomo czy i nie wiadomo kiedy
Konfrontacja
Koniec