Kirjoittaja Aihe: Java - Kekomuistin täyttyminen on ongelma  (Luettu 3319 kertaa)

tetrao

  • Käyttäjä
  • Viestejä: 177
    • Profiili
Java - Kekomuistin täyttyminen on ongelma
« : 24.08.09 - klo:22.57 »
Java - Rekisteriviittauksen kadottaminen ajovuoron siirtyessä prosessilta toiselle (vanha otsake)

Tilanne tämä:

Minulla vuorottelee kaksi prosessia, niin että toinen saa ajoaikaa sekunnin aina sekunnin välein. Eli prosessi on sekunnin ajossa, sekunnin lepää, taas sekunnin ajossa jne.  Tarkoituksena olisi, että kun prosessi on ensimmäistä kertaa ajossa, niin siinä alustetaan muuttuja, jota käytetään jälkimmäisillä ajokerroilla.

Kysymys kuuluu: Miten saan alustettua muuttujan, niin että siihen pystytään viittaamaan jälkimmäisillä ajokerroilla?

Kyseessä on olio taulukko, jonka olen luonut new komennolla (Onko muita vaihtoehtoja?). Tiedän että taulukko löytyy muistista, mutta en pääse käsiksi siihen. Javassa kun ei pysty käyttämään muistiosoitteita viittaukseen.. 
« Viimeksi muokattu: 25.08.09 - klo:19.17 kirjoittanut tetrao »
Arch Linux - A simple, lightweight distribution

HannuTapio

  • Käyttäjä
  • Viestejä: 1264
  • OpenJDK + JavaScript testailuu ja säätelyy.
    • Profiili
    • Hannun netti internet sotaisa aihe lautapelejä.
Tilanne tämä:

Minulla vuorottelee kaksi prosessia, niin että toinen saa ajoaikaa sekunnin aina sekunnin välein. Eli prosessi on sekunnin ajossa, sekunnin lepää, taas sekunnin ajossa jne.  Tarkoituksena olisi, että kun prosessi on ensimmäistä kertaa ajossa, niin siinä alustetaan muuttuja, jota käytetään jälkimmäisillä ajokerroilla.

Kysymys kuuluu: Miten saan alustettua muuttujan, niin että siihen pystytään viittaamaan jälkimmäisillä ajokerroilla?

Kyseessä on olio taulukko, jonka olen luonut new komennolla (Onko muita vaihtoehtoja?). Tiedän että taulukko löytyy muistista, mutta en pääse käsiksi siihen. Javassa kun ei pysty käyttämään muistiosoitteita viittaukseen.. 

Hei!

Sinä hieman vaikeasti kirjoitit, ja kun en itsekkään ole kunnon Java koulutuksesta nauttiva, ainoastaan harraste mielin liikkeellä, niin yritän vastata.
En aivan ymmärrä mitä yrität, onko sinulla siis yksi Thread joka lepää sekunnin ja on sekunnin aktiivisena.

Java ohjelma lepää Thread.sleep (ms); käskyllä, sinun ei tarvitse uudelleen alustaa luokkaa joka sekunnin välein, se vain kerää garbagea.
Miksi et voisi käyttää alustamiasi muuttujia myös sleep(ms); käskyn jälkeen.

Lisäksi jos haluat että luomasi luokka munluokka luokka1 = new munluokka (); kopioituu vaikka munluokka luokka2 = new munluokka(); luokkaan.
Niin kirjoitat vain luokka2 = luokka1; Javassa ei ole pointtereita, mutta kyllä sillä pystyy kopioimaan "tavallaansa" muistiosoitteita.

Tämä luokka2 = luokka1 riittää siis kopioimaan alustamasi muuttujat, vaikka nullaisit luokka1 aika ajoin !!

Kehittyneemmät Javailijat voivat täydentää!

//----

Kiitos,,

« Viimeksi muokattu: 25.08.09 - klo:07.58 kirjoittanut JariTapio »
Suomalainen Linux netti lautapelejä indie .. ( Gimp, Inkscape, Netbeans, Audacity ) ..
Blogi - [ https://lautapelimestari.com ]
Pelisivut - [ https://lautapelisivusto.com | https://hannunsankarit.com | https://lautapelikenraalit.com ]
--

tetrao

  • Käyttäjä
  • Viestejä: 177
    • Profiili
Lainaus
En aivan ymmärrä mitä yrität, onko sinulla siis yksi Thread joka lepää sekunnin ja on sekunnin aktiivisena.
Joo, laiton vähän huonosti tuon, joten minäpä tarkennan. Eli kun sanoin prosessin olevan levossa, niin tarkoitin että se ei ole ajossa ollenkaan. Ehkä olisi selkeämpi kuvata prosessia luokkana, jolle jokin "suurempi luokka" antaa suoritusaikaa sekunnin välein. Tämä suurempi luokka on itsellekin "pimiö", joten en tiedä millä periaatteella se suoritusaikaa jakelee. Sen tiedän että tämä "minun luokka" ei nuku sleepillä. se vain hyrrää for -silmukassa suorittaen eri operaatioita sekunnin, kunnes tämä "suurempi luokka" käskyttää lopettaamaan (time counter).

Lainaus
sinun ei tarvitse uudelleen alustaa luokkaa joka sekunnin välein, se vain kerää garbagea.
Tämä on juuri se minun ongelma. Jos varaan tilaa luokka olio taulukolle sekunnin välein, niin noin kymmenennellä ajokerralla heap - muisti täyttyy ja Java ilmoittaa virheestä.

Toisaalta, jos en varaa tilaa, niin ongelmia syntyy siihen viitatessa. Kun yritän sijoittaa taulukkoon olion, niin Java ilmoittaa, että ei tunnista aluetta, eli se tila tulisi varata.

Minäpä yritän konkretisoida tilannetta:

Koodia: [Valitse]
if (firstTimeRunning)
     Array [] TestArray=new Array[SIZE];
else
     TestArray[0]=Array0;  // ei onnistu esim. toisella ajokerralla, koska Java ei ilmeisesti Tunne aluetta TestArray ?

esim. int muuttuja löytyy muistista vielä toisellakin ajokerralla, niin tällä olettamalla, miksei TestArray:kin löytyisi?

lisäys: Jos oikein ymmärsin tuon Javan muistinvaraus idean, niin se tosiaan varaa Keosta tilaa joka ajokerta Array*SIZE verran, mikäli yllämainittua if else rakennetta ei käytetä. Kymmenennellä ajokerralla minulla olisi tällöin 10 taulukko muistissa, joista tunetaan viittaukset vain yhteen, eli uusimpaan. Miten onnistun säilyttämään ensimmäisellä ajokerralla taulukkoa luodessa viittauksen, niin että ei tarvitsisi luoda uutta taulukkoa siirtyessä uudelleen ajoon?     
« Viimeksi muokattu: 25.08.09 - klo:15.52 kirjoittanut tetrao »
Arch Linux - A simple, lightweight distribution

tetrao

  • Käyttäjä
  • Viestejä: 177
    • Profiili
Vs: Java - Kekomuistin täyttyminen on ongelma
« Vastaus #3 : 25.08.09 - klo:16.09 »
Laitan uutena viestinä, kun ongelma muuttui:

Lainaus
if (firstTimeRunning)
     Array [] TestArray=new Array[SIZE];
else
     TestArray[0]=Array0;  // ei onnistu esim. toisella ajokerralla, koska Java ei ilmeisesti Tunne aluetta TestArray ?

Tuo toimii, kun muuttaa tälläiseksi:

Koodia: [Valitse]
Array [] TestArray;

if (firstTimeRunning)
     TestArray=new Array[SIZE];
else
     TestArray[0]=Array0; 

Tästä huolimatta heap-muisti täyttyy, eli muistin täyttyminen ei johdu tästä:
Lainaus
Kymmenennellä ajokerralla minulla olisi tällöin 10 taulukko muistissa, joista tunetaan viittaukset vain yhteen, eli uusimpaan.

Sen sijaan, jos teen joka vuoro toimenpiteen Array [] TestArray=new Array[SIZE] , niin muisti ei täyty, mutta tilan varaus vie aikaa.

Mietinkin nyt että mikä täyttää muistin n.10 ajokerran jälkeen?

lisäys: Aikani kokeiltuani rupean olemaan ihan ristissä tämän Javan muistinkäytön ja siihen kuluvan ajan kanssa.  Kaipailisin selvennystä tähän:
Array [] TestArray=new Array[suuri luku] luonti ei vissiin itsessään vie paljon aikaa, vaan suureen taulukkoon viittaaminen vie ja muistia ei kulu ennenkuin taulukkoon sijoitetaan jotain. Onko totta?
« Viimeksi muokattu: 25.08.09 - klo:20.07 kirjoittanut tetrao »
Arch Linux - A simple, lightweight distribution

Tommi S.

  • Käyttäjä
  • Viestejä: 240
    • Profiili
Vs: Java - Kekomuistin täyttyminen on ongelma
« Vastaus #4 : 26.08.09 - klo:19.20 »
Minulla ei ole juuri minkäänlaista kokemusta Javasta, eli ihan C++ -pohjalla arvailen, mutta jos sinulla on kaksi prosessia jotka vuorottelee, niin eikö tämän voisi tehdä siten että sinulla on kaksi oliota joita se pääprosessi käskyttää, ja eikö näihin olioihin saa luomisvaiheessa varattua sitä taulukkoa sinne sisälle, niin että se taulukko varataan vain kerran kun se olio luodaan, ja sen olion metodi näkee sen sisäisen taulukon, niin ettei prosessin tarvitse varata joka suorituskerralla uutta taulukkoa.

Pseudokoodina jotenkin näin:

Koodia: [Valitse]
luokka Olio:
    init(self): // tämä kutsutaan kun luodaan uusi olio
      new self.Taulukko // varataan olion sisälle taulukko
     
    prosessi(self): // tämä on se prosessi jota pääprosessi käskyttää
      for i=0 ... {
      self.Taulukko = funktionPaluuarvo() // prosessi käyttää olion sisäistä taulukkoa
      }

tetrao

  • Käyttäjä
  • Viestejä: 177
    • Profiili
Vs: Java - Kekomuistin täyttyminen on ongelma
« Vastaus #5 : 26.08.09 - klo:20.51 »
Minulla ei ole juuri minkäänlaista kokemusta Javasta, eli ihan C++ -pohjalla arvailen, mutta jos sinulla on kaksi prosessia jotka vuorottelee, niin eikö tämän voisi tehdä siten että sinulla on kaksi oliota joita se pääprosessi käskyttää, ja eikö näihin olioihin saa luomisvaiheessa varattua sitä taulukkoa sinne sisälle, niin että se taulukko varataan vain kerran kun se olio luodaan, ja sen olion metodi näkee sen sisäisen taulukon, niin ettei prosessin tarvitse varata joka suorituskerralla uutta taulukkoa.

Pseudokoodina jotenkin näin:

Koodia: [Valitse]
luokka Olio:
    init(self): // tämä kutsutaan kun luodaan uusi olio
      new self.Taulukko // varataan olion sisälle taulukko
     
    prosessi(self): // tämä on se prosessi jota pääprosessi käskyttää
      for i=0 ... {
      self.Taulukko = funktionPaluuarvo() // prosessi käyttää olion sisäistä taulukkoa
      }

Juurikin näinhän se olisi pitänyt tehdä, nyt ei muisti enää täyty. Kiitos!

Pitäisi varmaan otsikkoa taas muuttaa, mutta kärsiikö kysyä vielä vinkkejä tuohon ajan optimointiin? Käyttämäni taulukon koko kasvaa hieman joka ajovuoro, joten joudun alustaessa tekemään valmiiksi liian suuren taulukon ensimmäisille kierroksille. Ongelman voisi tietysti kiertää luomalla joka ajovuoro uuden hieman suuremman taulukon, mutta veikkaan että sekin saattaa osoittautua liian aikaa vieväksi ja pahimmassa tapauksessa tuo muistin täyttymis ongelma palautuu.. En ole huomannut, että taulukon tilaa varatessa olisi mennyt ylenpalttisesti aikaa, joten ongelman täytyy piileä suureen taulukkoon viitatessa. Käyttääkö Java Kekomuistia kaikkien muuttujien säilöntää varten, vai onko jotain muitakin muisteja ja kuinka kauan aikaa menee muistiin kirjoittamiseen/tiedon hakemiseen muistista?   

ps. on kyllä offtopicia       
Arch Linux - A simple, lightweight distribution

ilkkak

  • Käyttäjä
  • Viestejä: 405
    • Profiili
Vs: Java - Kekomuistin täyttyminen on ongelma
« Vastaus #6 : 30.08.09 - klo:21.19 »
Heap tulee täyteen, jos pinoat liikaa metodikutsuja. Tämä tapahtuu yleensä rekursiivisissa metodeissa jos niissäkään.
Eli, jos saat pinon täyteen, ohjelmassasi on suunnitteluvirhe :).


Metodin loppuun (for silmukkaan tms.)

try {
  Thread.sleep(1000); // sammutus sekunniksi
} catch InterruptedException e {} // Loppuu tarvittaessa

Lisäksi voit liputtaa lopetusehdon tms.


Kokeile mureakuhaa, jos sieltä tulisi selkeä ohje.