zmiany rozmiaru dostępnej pamięci

zmiany rozmiaru dostępnej pamięci
PI
  • Rejestracja:prawie 14 lat
  • Ostatnio:ponad 13 lat
0

W pisanym programiku chciałbym, aby jego możliwości zależały (ograniczały się) od ilości pamięci RAM komputera, na którym jest uruchamiany. (aplikacja jest w postaci pliku .jar)
Czy jest to w ogóle możliwe i jak to wykonać?

Mniej więcej widziałbym to tak:

  1. program uruchamia obszar roboczy- z takimi ustawieniami ze u kazdego sie odpali.
  2. jesli wybierze sie plik-->nowy to wyskakuje okno gdzie mozna podac ustawienia nowego projektu.
    No i wlasnie tutaj chcialbym sprawdzac ilosc wolnej pamieci RAM (nie tylko wartosci maksymalnej przydzielonej JVM) i na tej podstawie mowic użytkownikowi:" Ok-zgadzam sie na taki projekt"; lub: "Nie ma szans-za malo pamieci".

W przypadku zgody nastepuje zwiekszenie pamieci przydzielonej JVM.

Czy takie dynamiczne zmiany z poziomu aplikacji pamieci JVM sa w ogole mozliwe (jak to wykonac?)?
Jesli nie, to czy pozostaje jedynie przydzielenie aplikacji skonczonego zasobu pamieci w chwili jej uruchomienia? Czy jest moze jeszcze jakies inne rozwiazanie na ktore nie wpadlem.

Olamagato
  • Rejestracja:ponad 16 lat
  • Ostatnio:13 dni
  • Lokalizacja:Polska, Warszawa
  • Postów:1058
0

Podejście 1. W projekcie ustawiasz maksymalną możliwą wartość rozmiaru pamięci (-xmx1500m). Java i tak przydzieli sobie na starcie domyślną minimalną wielkość, a potem tylko tyle ile będzie w stanie (zwykle jest to do 1,5 GB RAM na wersji 32-bit) ponieważ potrzebuje przydziału największego spójnego obszaru. Wtedy program javowy będzie miał do dyspozycji tyle pamięci w VM ile faktycznie będzie możliwe.
Podejście 2. Robisz projekt z najmniejszymi możliwymi ustawieniami, które będą w stanie załadować najmniejsze gui. Wielkość dostępnej pamięci sprawdzisz przez jni i na tej podstawie odpalisz (lub nie) inną aplikację z maksymalnymi realnie możliwymi ustawieniami pamięci za pomocą wywołania java.exe.

W praktyce to pierwsze podejście jest prostsze i szybsze bo java nie bierze od początku tyle ile może, chyba że to wymusisz przez -xms. Jeżeli jednak aplikacja weźmie całą maksymalną pamięć, to pamięć VM rozrośnie się do prawie 2GB i już nie zwolni aż do zamknięcia JVM. Zwolnienia pamięci przez aplikację nic już nie dadzą ponieważ JVM nie potrafi oddawać pobranej od systemu pamięci. Oddaje tylko raz i to całą - kiedy jest zamykana. Krótko mówiąc - minimalny xms, maksymalny xmx, a aplikacja nie przydziela sobie pamięci jeżeli naprawdę nie potrzebuje.


Jeżeli ktoś komuś coś, ewentualnie nikt nikomu nic, to właściwie po co...?
PI
  • Rejestracja:prawie 14 lat
  • Ostatnio:ponad 13 lat
0

No dobra

  • spakowałem aplikację do jara,
  • zrobiłem plik startowy z poleceniem: java -Xms512m -Xmx512m -jar MojaNazwa.jar.

W jaki sposób teraz określać czy żądana liczba tworzonych obiektów nie doprowadzi do: " java.lang.OutOfMemoryError: Java heap space " ??
No bo chyba robienie tego w ten sposób:

Kopiuj
 
        (..)
	Runtime rt = Runtime.getRuntime();
        (...)
        System.out.println("Free memory: "+rt.freeMemory());

Nie prowadzi do niczego dobrego, gdyż metoda freeMemory() nie podaje ilości wolnej pamięci do granicy określonej parametrem -Xmx512m, a jedynie do końca aktualnie używanego jej rozmiaru ( ustawienie na starcie Xms=Xmx nie pomaga, gdyż i tak Xms jest mniejszy od Xmx). W trakcie tworzenia kolejnych elementów, gdy "dostępna pamięć" zbliża się do wyczerpania uruchamiany jest GarbageCollection i metoda freeMemory() ponownie wykazuje większą liczbę zasobów.
No i tak w kółko... aż do zawalenia całego heap'a.
Więc taki sposób nie zdaje egzaminu.

A może można od drugiej strony, tj. zamiast sprawdzać ilość pamięci do końca określać ilość pamięci już zajętej ??

Ktoś ma jakiś pomysł na to?

Wibowit
  • Rejestracja:prawie 20 lat
  • Ostatnio:około 11 godzin
0

Policzenie ile byłoby wolnego miejsca po odśmieceniu wg mnie trwałoby niewiele krócej (np 2x krócej) niż sam właściwy proces odśmiecania, a więc byłaby to kosztowna operacja. Musisz więc zasugerować JVM odpalenie GC, poczekać na zakończenie odśmiecania i wtedy pobrać wielkość pamięci. W okienku dialogowym, mówiącym o braku pamięci możesz dodać przycisk sugerujący JVM odpalenie GC oraz mierzyć co chwilę ilość raportowanej wolnej pamięci. Jeśliby ilość wolnej pamięci zwiększyła się ponad wymagany poziom to okienko znika i odpala się co się ma odpalać.


"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.
edytowany 1x, ostatnio: Wibowit
PI
  • Rejestracja:prawie 14 lat
  • Ostatnio:ponad 13 lat
0

Wibovit:
Jak już mówiłem ustawienie -Xms na 512m, nie jest wykazywane przez metodę freeMemory(). Podaje ona jedynie jakaś wartość dostępna zanim nastąpi odpalenie GC.
Gdyby zrobić tak jak sugerujesz to:

  1. Rozumiem z tego co mówisz że kolejne wywołania GC mają dążyć w kierunku umożliwienia mi wartości podanej w parametrze -Xms ?
  2. Jeśli nawet w pętli sprawdzałbym czy na skutek kolejnych wywołań GC jest już ileś tam pamięci, to by wiedzieć czy ta ilość jest wystarczająca musiałbym przeliczyć ile pamięci potrzeba do utworzenia liczby obiektów, której potrzebuje.
    Z tego co czytałem do tej pory to do wyznaczenia pamięci potrzebnej dla tablicy obiektów nie wystarczy znajomość ilości pamięci potrzebnej na jeden obiekt i pomnożenie tego razy ich ilość. Tym bardziej jeżeli jest to tablica wielowymiarowa (dochodzą tam jeszcze jakieś wskaźniki....). Np tablica obiektów obiekty[a][b][c] wymaga innej wielkości zasobów niż tablica obiekty[c][b][a] (założenia a,b,c, to inne liczby).
    Jaki jest na to przelicznik?
Olamagato
Tablice w Javie są nierówne (rugged), czyli w ramach tego samego wymiaru poszczególne wiersze (podtablice) mogą mieć inne długości. A tablice wielowymiarowe, to nic innego jak tablice referencji do tablic. Stąd ta kolejność jest istotna. Możesz zrobić tablicę, której rozmiar każdej podtablicy (np. w int[][][][]), każdego wymiaru jest liczbą losową. Dlatego umieszczania liczb w nawiasach kwadratowych przy deklaracji tablic nie ma żadnego sensu. Równość tablic (taka jak w C/C++) jest w Javie tylko przypadkiem szczególnym.
Olamagato
  • Rejestracja:ponad 16 lat
  • Ostatnio:13 dni
  • Lokalizacja:Polska, Warszawa
  • Postów:1058
0

Java ma nieco "zmanipulowane" wielkości tego co nazywa się pamięcią.
Sprawa wygląda tak:

  1. Cała zadeklarowana pamięć możliwa do przydzielenia dla bieżącego procesu JVM to wynik metody: Runtime.maxMemory(). Jest to odpowiednik odczytania wartości opcji -xmx.
  2. Cała pamięć aktualnie przydzielona od systemu dla bieżącego procesu JVM to wynik metody: Runtime.totalMemory()
  3. Cała już użyta pamięć, to wynik działania: Runtime.totalMemory() - Runtime.freeMemory()
  4. A cała wolna pamięć możliwa do użycia to wynik działania:
    Runtime.freeMemory() + Runtime.maxMemory() - Runtime.totalMemory()
    W tym ostatnim przypadku jeżeli po sprawdzeniu tej wielkości jakieś inne procesy (nie Javowe) zabiorą od systemu pamięć, to JVM może nie otrzymać od systemu dodatkowej pamięci (do granicy Runtime.maxMemory()) bo pamięć procesów "niejavowych" + pamięć wszystkich procesów JVM musi być nie większa niż cała pamięć wirtualna systemu. Stan taki może się zdarzyć w systemach 32-bitowych z maks. 2 GB RAM bez ustawionego swapfile.

Nie ma kompletnie znaczenia czy bawimy się gc czy nie, a skutek jego działań nie zmieni wartości wolnej pamięci liczonej w punkcie 4.

Runtime.freeMemory() oznacza tak naprawdę ilość pamięci "totalnie wolnej", czyli takiej której zajęcie nie spowoduje ani działania odśmiecarki, ani wywołania systemowego (czyli nie spowoduje niekontrolowanego narzutu użycia CPU).
Tak dokładna informacja o wolnej pamięci jest potrzebna niezwykle małej grupie programów javowych - np. tym "sławnym" aplikacjom Javowym do kontroli ruchu lotniczego ;).

Jeszcze co do użycia pamięci. Każdy najmniejszy obiekt (w tym obiekt dowolnej tablicy zeroelementowej) zajmuje 16 bajtów, każde pole obiektowe (czyli każda referencja 32-bitowa) zajmuje 4 bajty, a pole proste tyle ile jest określone w definicji języka (np. long, to 64-bity czyli 8 bajtów).
Tak więc pamięć przydzielaną na każdy obiekt można policzyć na sucho (co jest założeniem Javy). Nie jestem jednak pewien jak wygląda sprawa z liczeniem zajętości pakowanych referencji 64-bitowych bo nie przeryłem jeszcze całej specyfikacji Java 7.


Jeżeli ktoś komuś coś, ewentualnie nikt nikomu nic, to właściwie po co...?
edytowany 5x, ostatnio: Olamagato
Wibowit
  • Rejestracja:prawie 20 lat
  • Ostatnio:około 11 godzin
0

OutOfMemoryError można od biedy łapać. Zakładając, że przerwanie jakiejś funkcji alokującej obiekt spowoduje powstanie wielu niedostępnych obiektów (czyli śmieci, w terminologii platform zarządzanych), to po wystąpieniu tego błędu GC powinno te obiekty zebrać i zwolnić pamięć.

NetBeans Platform, dla przykładu, łapie błędy typu OutOfMemoryError, a potem resetuje moduł, który ten błąd spowodował. Raz miałem coś takiego, że parser wpadał w jakąś okropną rekurencję i zapychał całą pamięć. NetBeans w takim przypadku po prostu wyłączał parser na danym kodzie źródłowym.


"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.
PI
  • Rejestracja:prawie 14 lat
  • Ostatnio:ponad 13 lat
0

No więc tak... (dużo tego się nazbierało):
Zacząłem od ustalenia ile zajmują obiekty, które tworze. Skorzystałem do tego z małego programiku znalezionego tutaj:
http://www.roseindia.net/javatutorials/determining_memory_usage_in_java.shtml

No i wynik jest 472 bajty na obiekt mojej klasy "Panelik". W innej klasie (klasie głównej programu) tworze obiekty tej klasy dodajac do nich listenera (fragmet kodu):

Kopiuj
 
      pole[k][i][j] = new Panelik();
      obsluga obsl = new obsluga(k,i,j);
      pole[k][i][j].addMouseListener(obsl);

Ile zajmuje klasa obsluga? Wychodzi na to ze 24bajty. Sprawdzone rownież tym samym programikiem. No i dla pewności sprawdziłem jeszcze, ile zajmuje obiekt klasy Panelik wyposazony w takiego listenera, no i jest 496 bajtow. (Pomijam milczeniem to jak bardzo mało efektywne jest: a) tworzenie tablicy 3 wymiarowej tak duzych obiektow, b) dodawanie tego MouseListenera . Niestety wcześniej nie zdawałem sobie z tego sprawy, no ale zostawmy to, bo akurat tutaj wiem co i jak poprawić. Tak czy siak widze inny problem w calym tym dzialaniu.
Mianowicie:
Podazylem za sugestia i podpowiedziami Olamagato, tj: ustawilem identyczne wartosci dla Xms i Xmx oraz wykorzystuje metody Runtime'a w przedstawiony wczesniej sposob. Czyli. uruchamiam cala aplikacje z jakimis podstawoymi ustawieniami. Na koniec sprawdzam ile to wszystko zajelo pamieci. Aplikacje mozna podzielc na czesc "o niezmiennej wielkosci" (stalej bez wzgledu na wielkosc realizowanego projektu) oraz "czesc zmienna". Do obliczenia ilosci zajmowanej pamieci przez "czesc zmienna" stosuje napisana metode (przelicznik na podstawie opisu wspomnianego przez Olamagato. Zakladam ze moj przelicznik jest prawidlowy, gdyz przedstawia wartosci zgodne z programikiem znalezionym w necie)
No i teraz w momencie gdy uzytkownik decyduje ze program oferuje mu zbyt male mozliwosci pobieram wartosci ktorych on żada. I dokonuje sprawdzenia warunku:
("waga" calej aplikacji) - ("waga" jej "części zmiennej")+("waga" żądanej części zmiennej (z przelicznika)) < mojRuntime.maxMemory() ;

No i do tego co dłużej nie jest potrzebne przypisuje null'e i tworze nowe, odpowiednio wieksze poszczegolne skladowe.

Do obserwacji tego co dzieje się z pamięcią używam JConsole i zastanawia mnie kilka rzeczy:

  1. Czy wskazane jest takie maksymalne zapychanie pamięci,czy może jakiś procent dobrze byłoby pozostawić wolny (jaki?) ?

  2. Czy dobrze by bylo ustawic JVM jakies jeszcze parametry poza -Xmx i Xms dotyczace podzialu poszczegolnych czesci heap'a (jakie?) ?.

  3. Zastanawia mnie rowniez sam GC. No bo chyba mozna go tez jakos dobrac, wydaje mi sie ze nie ma on zbyt duzo roboty poza momentami wywolywanych przeze mnie przeladowan (myslalem nad "Concurrent Low Pause Collector" aby posprzatac raz a dobrze zamiast angazowac GC czesto bez sensu.

(To moje pierwsze zetkniecie z obsluga Jconsole i tematem GC, więc prosze o wyrozumialość. )

aa... i jeszcze jedno, zauważylem ze metoda maxMemory() zwraca rozne wartosci nawet w niewielkich odstepach czasu (rowniez w jconsole zauwazam przebieg piłokształtny zajętej pamięci), co chyba moze powodowac katastrofe jesli dokonuje sprawdzenia warunku przedstawionego wyzej?

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)