Kaip elgtis su "java.lang.OutOfMemoryError: Java heap space" klaida?

Rašau kliento pusės Swing programą (grafinis šriftų dizaineris) Java 5. Pastaruoju metu susiduriu su java.lang.OutOfMemoryError: Java heap space klaida, nes nesu konservatyvus atminties naudojimo atžvilgiu. Vartotojas gali atidaryti neribotą skaičių failų, o programa atidarytus objektus saugo atmintyje. Greitai pasidomėjęs radau Ergonomics in the 5.0 Java Virtual Machine ir kitus, kuriuose teigiama, kad "Windows" kompiuteryje JVM numatytasis maksimalus krūvos dydis yra 64 MB.

Atsižvelgiant į šią situaciją, kaip turėčiau elgtis su šiuo apribojimu?

Galėčiau padidinti max heap size naudodamas command line parinktį prie Java, bet tam reikėtų nustatyti turimą RAM ir parašyti kokią nors paleidimo programą ar skriptą. Be to, padidinus iki tam tikro galutinio maksimalaus dydžio, problema nebus išspręsta.

Galėčiau perrašyti kai kuriuos savo kodus, kad objektai dažnai išliktų failų sistemoje (duomenų bazės naudojimas yra tas pats) ir taip atlaisvinčiau atmintį. Tai galėtų suveikti, bet tikriausiai irgi daug darbo.

Jei galėtumėte nurodyti, kaip išsamiau išdėstyti pirmiau minėtas idėjas arba kokias nors alternatyvas, pavyzdžiui, automatinė virtualioji atmintis, dinaminis krūvos dydžio išplėtimas, būtų puiku.

Sprendimas

Galiausiai visada galite naudoti maksimalų galimą krūvos kiekį, nesvarbu, kokioje platformoje dirbate. "Windows" 32 bitų sistemoje tai yra apie 2 GB (ne konkrečiai krūvos, o visos atminties vienam procesui). Taip jau atsitiko, kad "Java" pasirinko mažesnį numatytąjį dydį (tikriausiai tam, kad programuotojas negalėtų kurti programų, kuriose atminties paskirstymas bėga į priekį, nesusidūręs su šia problema ir neturėdamas tiksliai ištirti, ką jis daro).

Taigi, atsižvelgiant į tai, yra keli būdai, kuriais galite nustatyti, kokio atminties kiekio jums reikia, arba sumažinti naudojamos atminties kiekį. Viena iš dažniausių klaidų naudojant tokias šiukšlių surinkimo kalbas, kaip "Java" ar C#, yra išlaikyti nuorodas į objektus, kurių nebenaudojate, arba priskirti daug objektų, nors vietoj to galėtumėte juos panaudoti pakartotinai. Kol objektai turi nuorodą į juos, jie ir toliau naudos krūvos erdvę, nes šiukšlių surinkėjas jų neištrins.

Tokiu atveju galite naudoti "Java" atminties profiliavimo programą, kad nustatytumėte, kurie jūsų programos metodai paskirsto daug objektų, ir tada nuspręstumėte, ar yra būdas užtikrinti, kad į juos nebeliktų nuorodų, arba apskritai jų neskirti. Viena iš galimybių, kurią anksčiau naudojau, yra "JMP" .

Jei nustatysite, kad šiuos objektus alokuojate dėl tam tikros priežasties ir jums reikia išlaikyti nuorodas (priklausomai nuo to, ką darote, taip gali būti), jums tiesiog reikės padidinti maksimalų krūvos dydį paleidžiant programą. Tačiau atlikę atminties profiliavimą ir supratę, kaip paskirstomi jūsų objektai, turėtumėte geriau suprasti, kiek atminties jums reikia.

Apskritai, jei negalite užtikrinti, kad jūsų programa veiks tam tikrame baigtiniame atminties kiekyje (galbūt priklausančiame nuo įvesties dydžio), visada susidursite su šia problema. Tik visa tai išnaudojus, jums reikės pasidomėti objektų spartinimu diske ir pan. Šiuo metu turėtumėte turėti labai rimtą priežastį pasakyti "Man reikia Xgb atminties" ir negalite to apeiti tobulindami savo algoritmus ar atminties paskirstymo modelius. Paprastai taip būna tik su dideliais duomenų rinkiniais dirbančių algoritmų atveju (pvz., duomenų bazės ar mokslinės analizės programos), tada tokie metodai kaip spartinančioji atmintis ir į atmintį atvaizduotas IO tampa naudingi.

Komentarai (1)

Paleiskite "Java" su komandinės eilutės parinktimi -Xmx, kuri nustato mažiausią krūvos dydį.

Išsamesnės informacijos žr. čia.

Komentarai (3)

Taip, naudodami -Xmx galite sukonfigūruoti daugiau JVM atminties. Kad būtumėte tikri, jog atminties nepraleisite ir nešvaistysite. Padarykite krūvos išrašą ir naudokite Eclipse Memory Analyzer, kad išanalizuotumėte atminties suvartojimą.

Komentarai (1)