GC - zmuszenie do zwolnienia pamięci

GC - zmuszenie do zwolnienia pamięci
AR
  • Rejestracja:prawie 15 lat
  • Ostatnio:ponad 4 lata
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.

edytowany 2x, ostatnio: arrowman
Wibowit
  • Rejestracja:prawie 20 lat
  • Ostatnio:15 minut
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.
AR
  • Rejestracja:prawie 15 lat
  • Ostatnio:ponad 4 lata
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?

edytowany 4x, ostatnio: arrowman
Wibowit
  • Rejestracja:prawie 20 lat
  • Ostatnio:15 minut
2

Dispose usuwa obiekt? http://4programmers.net/Forum/C_i_.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.
AR
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.
Wibowit
Musisz w końcu zacząć rozróżniać zasoby zarządzane od niezarządzanych. Dispose czy podobne metody odnoszą się do zasobów niezarządzanych.
AR
Aha, dzięki, zapamiętam.
Olamagato
  • Rejestracja:ponad 16 lat
  • Ostatnio:4 dni
  • Lokalizacja:Polska, Warszawa
  • Postów:1058
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...?
AR
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?
Olamagato
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ść.
Wibowit
  • Rejestracja:prawie 20 lat
  • Ostatnio:15 minut
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.org/u64q/benchmark.php?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.
Olamagato
  • Rejestracja:ponad 16 lat
  • Ostatnio:4 dni
  • Lokalizacja:Polska, Warszawa
  • Postów:1058
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...?
LO
  • Rejestracja:ponad 19 lat
  • Ostatnio:około 4 lata
0

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

Kopiuj
 
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/javase/7/docs/api/java/lang/System.html#gc%28%29

edytowany 2x, ostatnio: LOSMARCELOS
bogdans
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ć."
AR
"Wywołanie GC po usunięciu referencji na obiekt nie pomaga. GC i tak nie zwalnia pamięci.":-) Ale dzięki za chęci.
Koziołek
Moderator
  • Rejestracja:prawie 18 lat
  • Ostatnio:około miesiąc
  • Lokalizacja:Stacktrace
  • Postów:6821
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.


Sięgam tam, gdzie wzrok nie sięga… a tam NullPointerException
AR
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
Koziołek
Takie sztuki to tylko w C. Java z założenia nie pozwala na pracę z pamięcią.
AR
Mam na celu C++ QT, więc jak się wezmę za to, to nie omieszkam się pobawić:-)
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)