GC - zmuszenie do zwolnienia pamięci

Odpowiedz Nowy wątek
2011-10-06 19:03
0

Szanowni forumowicze,
Chciałbym się dowiedzieć czy można zmusić GC, albo cokolwiek aby usunęło mi instancję obiektu utworzonego operatorem new?
Wywołanie GC po usunięciu referencji na obiekt nie pomaga. GC i tak nie zwalnia pamięci.

Obiekt nigdzie indziej nie ma referencji, więc w tym wypadku jest to bezpieczne, szukałem już dużo, pytałem się ludzi, ale każdy mi pisał, żebym się tym nie zajmował. Tylko chcę zapytać z ciekawości, przy tworzeniu gier w JAVA o chyba musi być jakoś implementowane?
Zauważyłem, że obiekty w JAVA jakoś szybko poza Eden. Jak jakiś obiekt zajmuje kilkadziesiąt MB to może być czsami problem i chyba jest bo aplikacje w JAVA są raczej pamięciożerne.


"Ten, de profundis, z ciemnego kurhanu
Na trąbę powstanie. " Juliusz Słowacki

"Polacy! Gdyby Spartanie odżyli i zobaczyli Wasz heroizm i bohaterstwo, waleczny i dzielny ten naród schyliłby przed Wami czoło. Polska nie może być zwyciężona." - J.Bryan
edytowany 2x, ostatnio: arrowman, 2011-10-06 19:03

Pozostało 580 znaków

2011-10-06 19:15
1

Generalnie to nawet delete w C++ nie musi od razu zwalniać pamięci. Powinieneś po prostu zastosować się do poradników dotyczących alokacji pamięci z generacyjnymi odśmiecaczami - najlepiej, aby tworzone obiekty albo były natychmiastowo osieracane (tzn zwalniane referencje do nich) albo były długowieczne.

Wywołanie System.gc() to tylko podpowiedź dla odśmiecacza, którą może całkowicie zignorować.


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.

Pozostało 580 znaków

2011-10-06 19:31
0

Ale nie ma nic natywnego w JAVA do usuwania obiektu z pamięci? Nic, tak w ogóle?

W C# obiekty miały dispose(), pomimo tego, że jest GC.
Jak sobie pisałem gierkę w C# to mi to ułatwiało wiele spraw. Tutaj musiałbym za każdym razem np. usuwania pocisku wywalić go tylko z listy rysowanych elementów (no i kolizji itp.) i czekać aż łaskawie Szanowny Pan GC zechce sobie to usunąć, a jak obiekt trafi poza eden to dupa blada. A jak się ma kod rozwijany systematycznie np. przez rok, to się nie chce szukać wszytkich referencji. Bo zauważyłem, że jak mam 2 obiekty, do których są usunięte referencje, ale one mają do siebie referencje to GC nie usunie ich....
W C# robiłem sobie z pociskiem dispose() i grało:-) Żadnego zamiatania pod dywan. A jak pocisków są miliony? I potem miliony odłamków z tych milionów?


"Ten, de profundis, z ciemnego kurhanu
Na trąbę powstanie. " Juliusz Słowacki

"Polacy! Gdyby Spartanie odżyli i zobaczyli Wasz heroizm i bohaterstwo, waleczny i dzielny ten naród schyliłby przed Wami czoło. Polska nie może być zwyciężona." - J.Bryan
edytowany 4x, ostatnio: arrowman, 2011-10-06 19:39

Pozostało 580 znaków

2011-10-06 19:46
2

Dispose usuwa obiekt? http://4programmers.net/Forum/Ci.NET/78245-Co_wlasciwie_robi_metoda_dispose

Wątpię, aby była jakakolwiek metoda do usuwania obiektu zarządzanego z pamięci. Referencje, czy to w C# czy Javie, albo są nullami albo prowadzą do żyjącego obiektu (być może z wywołanym na nim dispose() czy finalize() ale to już szczegół). Nie ma możliwości takiego usunięcia obiektu zarządzanego, aby pozostały po nim uszkodzone referencje.

Czemu jak obiekt trafi poza Eden to dupa blada? Odśmiecanie odśmiecaniu nierówne, w większości przejść analizowany jest tylko Eden, ale co jakiś czas wywracana jest cała sterta do góry nogami.


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
Ciekawe, dzięki. Po prostu z kursu do XNA było to tak ujęte, przynajmniej ja to tak zapamiętałem. Bardzo interesujące. - arrowman 2011-10-06 21:39
Musisz w końcu zacząć rozróżniać zasoby zarządzane od niezarządzanych. Dispose czy podobne metody odnoszą się do zasobów niezarządzanych. - Wibowit 2011-10-06 21:41
Aha, dzięki, zapamiętam. - arrowman 2011-10-06 21:49

Pozostało 580 znaków

2011-10-06 21:30
1
arrowman napisał(a)

Ale nie ma nic natywnego w JAVA do usuwania obiektu z pamięci? Nic, tak w ogóle?

W Javie w ogóle prawie nic nie ma natywnego. :)

Jak sobie pisałem gierkę w C# to mi to ułatwiało wiele spraw. Tutaj musiałbym za każdym razem np. usuwania pocisku wywalić go tylko z listy rysowanych elementów (no i kolizji itp.) i czekać aż łaskawie Szanowny Pan GC zechce sobie to usunąć

Przydział pamięci jest poza operacją na dysku najwolniejszą operacją jaką wykonuje JVM. Należy każdy new traktować pod względem wydajności podobnie jak czytanie z pliku - to znacznie ułatwi projektowanie czegokolwiek. Poza tym pozostawianie "niepotrzebnych" referencji, albo jest celowe, albo jest skutkiem błędu. Typowym przykładem jest zdejmowanie ze stosu referencji i nie wyczyszczenie ze stosu miejsca po niej - jednak czasem może to być celowe pozostawienie jako specyficzny rodzaj cache.

Bo zauważyłem, że jak mam 2 obiekty, do których są usunięte referencje, ale one mają do siebie referencje to GC nie usunie ich...

Bo usunie dopiero wtedy kiedy będzie brakowało wolnej pamięci w taki sposób, że JVM będzie musiało rozszerzyć swoją pamięć, przez pobranie kolejnej porcji z systemu. Wtedy dopiero obiekty będą masowo zwalniane, a wolne miejsce defragmentowane. To właśnie ta ostatnia operacja powoduje, że odśmiecanie jest bardziej efektywne, kiedy na raz da się zwolnić dużo. Jeżeli po każdej utracie referencji śmieciarz miałby odzyskiwać tę pamięć, to prowadziłoby to do takiej fragmentacji RAMu JVM, że w pewnym momencie i tak trzeba by było przeprowadzić bardzo kosztowną czasowo defragmentację. Efektywniej więc robić ją wtedy kiedy jest dużo obiektów do zwolnienia na raz.
Objawia się to tak, że zmniejsza się nieustannie "wolna" ilość pamięci i kiedy dojdzie ona do zera, to nagle odzyskuje się kilka do kilkudziesięciu MB na raz, następnie proces powtarza się. Oczywiście w sytuacji kiedy średnie użycie pamięci wciąż jest stałe. Kiedy rośnie, to JVM podwyższa pamięć przez zabranie jej systemowi i cały proces powtarza się na wyższym poziomie zużycia.

W C# robiłem sobie z pociskiem dispose() i grało:-) Żadnego zamiatania pod dywan. A jak pocisków są miliony? I potem miliony odłamków z tych milionów?

Polecenie new dlatego jest dość wolne, że właśnie kiedy śmieciarz odkryje dużą potrzebę przydziałów, a zupełnie nieużywanej pamięci jest za mało, to zaczyna zajmować się odśmiecaniem. Po prostu nie przejmuj się w ogóle nieużywanymi zasobami. Profiler pokaże, że jest to problem tylko jeżeli spore spowolnienia będą wyskakiwać cały czas w zupełnie losowych miejscach kodu. Ale jest to mało prawdopodobne.


Jeżeli ktoś komuś coś, ewentualnie nikt nikomu nic, to właściwie po co...?
Dzięki za tak szerokie wytłumaczenie. Polepszyło to moje uczucie niemocy:-) Swoją drogą to jak można unikać new w JAVA? Chodzi o używanie w miarę możliwości typów prostych? - arrowman 2011-10-06 21:42
Tak, ale nie koniecznie jako główną metodę. Dobre efekty może dać tworzenie potrzebnych obiektów zanim staną się potrzebne do obliczeń. W wypadku pocisków i odłamków można wcześniej utworzyć ich pulę, a po wykorzystaniu nie likwidować, ale oznaczyć jako "do użycia". Pogarsza to trochę jakość kodu jaką dają obiekty niezmienne, ale zyskuje wydajność. - Olamagato 2011-10-07 02:28

Pozostało 580 znaków

2011-10-06 21:38
2

Przydział pamięci jest poza operacją na dysku najwolniejszą operacją jaką wykonuje JVM. Należy każdy new traktować pod względem wydajności podobnie jak czytanie z pliku - to znacznie ułatwi projektowanie czegokolwiek.

A skąd takie rewelacje?
http://shootout.alioth.debian[...]test=binarytrees&lang=all
Zwykła alokacja + dealokacja jest szybsza w Javie niż w C/ C++. Pule obiektów w C/ C++ są szybsze w tym benchmarku, ale to chyba logiczne.


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.

Pozostało 580 znaków

2011-10-07 02:21
1
Wibowit napisał(a)

A skąd takie rewelacje?

Z własnego doświadczenia. Operacje alokacji i dealokacji są w Javie szybkie, to fakt. Ale nie szybsze niż wykonywanie pojedynczych instrukcji z jakich składa się kod (umownie źródłowy) Javy. Choćby z tego powodu, że alokacja lub odśmiecanie mogą wywoływać wykonanie całych serii takich instrukcji (nawet jeżeli będą one natywne/maszynowe). Kolega chce użyć Javy do gier. Dlatego bezpiecznie założyć, że dopóki nie ma operacji przydziału pamięci, to kod jest maksymalnie szybki. A operacje, które takie alokacje zawierają traktować jako potencjalnie wolniejsze od tych, które alokacji/dealokacji nie zawierają w ogóle.


Jeżeli ktoś komuś coś, ewentualnie nikt nikomu nic, to właściwie po co...?

Pozostało 580 znaków

2011-10-07 07:17
0

A próbowałeś użyć System.gc(); ?


Runs the garbage collector.

Calling the gc method suggests that the Java Virtual Machine expend effort toward recycling unused objects in order to make the memory they currently occupy available for quick reuse. When control returns from the method call, the Java Virtual Machine has made a best effort to reclaim space from all discarded objects.

The call System.gc() is effectively equivalent to the call:

     Runtime.getRuntime().gc()

See Also:
    Runtime.gc()

http://download.oracle.com/ja[...]ava/lang/System.html#gc%28%29

edytowany 2x, ostatnio: LOSMARCELOS, 2011-10-07 07:18
Czytałeś cały wątek? @wibowit napisał: "Wywołanie System.gc() to tylko podpowiedź dla odśmiecacza, którą może całkowicie zignorować." - bogdans 2011-10-07 07:58
"Wywołanie GC po usunięciu referencji na obiekt nie pomaga. GC i tak nie zwalnia pamięci.":-) Ale dzięki za chęci. - arrowman 2011-10-07 08:30

Pozostało 580 znaków

2011-10-07 11:56
0

Rzuć okiem do profilera i debugera. Możliwe, że zwolniłeś tylko jedną z referencji, ale wiszą jeszcze jakieś niejawne odwołania. Teoretycznie GC powinien umieć wykryć cykl osieroconych obiektów, ale nie zawsze to działa.

Tylko mi chodzi o taki hipotetyczny przypadek, a nie że mam problem z przeciekami. To swoją drogą:-) Przyśniła mi się po prostu pełna kontrola nad pamięcią i chciałem przenieść sen na jaw(v)ę:D - arrowman 2011-10-07 12:32
Takie sztuki to tylko w C. Java z założenia nie pozwala na pracę z pamięcią. - Koziołek 2011-10-07 12:38
Mam na celu C++ QT, więc jak się wezmę za to, to nie omieszkam się pobawić:-) - arrowman 2011-10-07 12:42

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0