Newsgroup: it.comp.java
Titolo: [aiuto][urgente] OutOfMemoryError

Salve a tutti!
sto lavorando con sequenze di dati moooooolto lunghe, con grosse
matrici e vettori e quindi quando mando in esecuzione il mio programma
incorro sempre in questo errore.
il parere che voglio chiedervi è il seguente: all'interno del mio main
richiamo diverse altre classi che fanno il "lavoro sporco" trattanto
con enormi quantità di dati, dopodichè io devo soltanto recuperare un
particolare vettore o matrice e tutto il resto potrei tranquillamente
buttarlo via. come faccio per forzare la liberazione della memoria che
queste classi occupavano? è possibile?
ho provato a richiamare continuamente System.gc() ma la memoria non si
svuota. oppure c'è un modo per ampliare la memoria disponibile della
JVM?
ringrazio anticipatamente quanti vorranno rispondere.
grazie e a presto!
giulio
-- 
"show me a sign to a life that shines
one direction into another sheltered peace of mind"
                               skid row
--
gpe...@BLAHlibero.it
rimuovi BLAH per rispondermi
   - God Bless -

 JVM?
usa come parametri
-Xmx256m -Xmn256m
in questo modo indichi alla JVM il valore massimo e minimo
della memoria (in questo caso 256MB) ... adattala al tuo caso
e fai delle prove
PS. cerca sul sito della sun per vedere tutti i parametri disponibili

-Xmx256m -Xmn256m
vi ho provato ma non ottengo miglioramenti...
e poi questi parametri non modificano le dimensioni dello heap in fase
di compilazione? io ne ho bisogno in fase di esecuzione.
cmq proverò...
ciao!


 di compilazione? io ne ho bisogno in fase di esecuzione.
in fase di compilazione???
un'altra opzione che ho notato influenza la performance
(ma da quello che ho capito per ora ti interessa solo la memoria)
sono -server / -client
ti posto due link
http://java.sun.com/docs/hotspot/VMOptions.html
http://java.sun.com/docs/hotspot/PerformanceFAQ.html
fammi sapere
ciao

 giulio
Il fatto che ti venga generato OutOfMemoryError dimostra
l'inutilità di chiamare System.gc().
La jvm quando non ha a disposizione memoria,
prima di generare OutOfMemoryError invoca autonomammente
il gc per liberare memoria.
Solo se non ci riesce genera l'eccezione.
Quindi è inutile che ti chiami System.gc.
Se ti è generata quell'eccezione potrebbe voler dire
che effettivamente la tua applicazione necessità di maggior memoria.
Per ottenerla è sufficiente invocare la JVM con le opzioni
-Xmx999999m -Xmn999999m con 999999 a piacere.
Però potrebbe essere anche il caso che la memoria in più
non ti sia necessaria perché la tua applicazione potrebbe avere
degli oggetti (ad esempio matrici/vettori, o elementi di
matrici/vettori) accessibili dal threads in esecuzione
ai quali tu però non accederai mai più.
In quest'ultimo caso è necessario che tu ispezioni con
accuratezza il tuo codice con lo scopo di individuare
questi oggetti e *solo* per questi oggetti settare
il corrispondente reference a null.
Ad esempio considera questa interfaccia VettoreGiocattolo
che serve a incapsulare un vettore:
interface VettoreGiocattolo {
   void set(int i, Object o);
   Object get(int i);
   void setSize(int s);
   int getSize();
}
E considera adesso la seguente classe MyVettoreGiocattolo
che realizza la precedente interfaccia:
public class MyVettoreGiocattolo implements VettoreGiocattolo {
   private Object[] v = new Object[10];
   private int size = v.length;
   public void set(int i, Object o) {
     if(i<0 || i>= size)
       throw new IllegalArgumentException();
     v[i] = o;
   }
   public Object get(int i) {
     if(i<0 || i>=size)
       throw new IllegalArgumentException();
     return v[i];
   }
   public void setSize(int s) {
     if(s<0)
       throw new IllegalArgumentException();
     if(s>size) {
       Object vnew[] = new Object[s];
       System.arraycopy(v, 0, vnew, 0, size);
       v = vnew;
     }
     size = s;
   }
   public int getSize() {return size;}
}
La precedente implementazione NON è corretta
dal punto di vista della accessibilità agli oggetti.
Ad esempio se nel tuo programma ci fossero alcuni di questi
MyVettoreGiocattolo ti potrebbe essere generata l'eccezione
OutOfMemoryError.
Potresti "tamponare" per un po' il problema
lanciando la JVM con più memoria
(opzioni -Xmx999999m -Xmn999999m viste sopra)
ma non avresti risolto il vero problema.
Lascio all'attento lettore (e soprattutto alla brava Claudia)
scoprire dove è l'errore e come correggerlo.
- Dario

secondo me l'errore è nel metodo setSize, ho alcuni dubbi, però...
chiamando System.arraycopy() vengono copiati
solo i riferimenti o tutto l'oggetto?
ho letto l'help ma non ho capito...
cioè all'inizio dico
private Object[] v = new Object[10];
questo alloca spazio per 10 Object e mantiene
un "puntatore" nella variabile v ad un'array
di puntatori. E' giusto?
(oppure è un'array di puntatori a oggetti?) bo?
quando dico:
v[i] = new Object()
cambio il "puntatore" i-esimo e il vecchio oggetto puntato,
se c'era, rimane pendente e può essere deallocato dal garbage collector
diversamente quando faccio:
Object vnew[] = new Object[s];
 System.arraycopy(v, 0, vnew, 0, size);
v = vnew;
mi riservo un nuovo spazio in memoria
ci copio i (riferimenti?) dell'oggetto v
assegno il "puntatore" v al nuovo indirizzo di memoria
appena creato
però, i vecchi "puntatori" v[] rimangono a puntare
ai loro oggetti e non vengono deallocati
mi sa che ho fatto un po' di casino ;-)

 }
La creazione di un oggetto MyVettoreGiocattolo pone l'allocazione iniziale
di 10 slot. Usare setSize() per impostare una dimensione maggiore porta
all'allocazione di un nuovo array in cui vengono copiati tutti i riferimenti
preesistenti. Impostando poi una dimensione minore, viene solo spostato il
"confine" logico (il membro "size") ma non viene fatta alcuna
riallocazione/copia dell'array interno, quindi, usandolo maldestramente, è
possibile arrivare ad un MyVettoreGiocattolo che mantiene riferimenti a
10000 oggetti, mentre solo 5 di questi risultano accessibili dall'esterno.
L'implementazione corretta di setSize() IMHO dovrebbe essere:
  ...
  public void setSize(int s) {
     if (s<0) throw new IllegalArgumentException();
     Object[] vnew = Object[s];
     //Copia solo i riferimenti necessari
     System.arraycopy(v, 0, vnew, 0, ((s>size)?size:s));
     v = vnew;
     size = s;
  }
  ...
In questo modo, qualunque richiesta di cambio di dimensioni porta
all'allocazione di un nuovo array, mentre il riferimento a quello vecchio si
perde nel vuoto, lasciando libertà di intervento al GC.
C'ho azzeccato? :P
-- 
Fermiamo Scientology prima che sia troppo tardi!!!
http://xenu.com-it.net
 - 
http://xenu.freewinds.cx/
(per rispondere personalmente leva IlDitoDalCulo)

 }
La creazione di un oggetto MyVettoreGiocattolo pone l'allocazione iniziale
di 10 slot. Usare setSize() per impostare una dimensione maggiore porta
all'allocazione di un nuovo array in cui vengono copiati tutti i riferimenti
preesistenti. Impostando poi una dimensione minore, viene solo spostato il
"confine" logico (il membro "size") ma non viene fatta alcuna
riallocazione/copia dell'array interno, quindi, usandolo maldestramente, č
possibile arrivare ad un MyVettoreGiocattolo che mantiene riferimenti a
10000 oggetti, mentre solo 5 di questi risultano accessibili dall'esterno.
L'implementazione corretta di setSize() IMHO dovrebbe essere:
  ...
  public void setSize(int s) {
     if (s<0) throw new IllegalArgumentException();
     Object[] vnew = new Object[s];
     //Copia solo i riferimenti necessari
     System.arraycopy(v, 0, vnew, 0, ((s>size)?size:s));
     v = vnew;
     size = s;
  }
  ...
In questo modo, qualunque richiesta di cambio di dimensioni porta
all'allocazione di un nuovo array, mentre il riferimento a quello vecchio si
perde nel vuoto, lasciando libertŕ di intervento al GC.


 C'ho azzeccato? :P
Hai perfettamente centrato il problema.
Complimenti!
Una implementazione alternativa, ma sempre corretta
dal punto di vista della accessibilità degli oggetti,
potrebbe essere anche la seguente:
   public void setSize(int s) {
     if(s<0)
       throw new IllegalArgumentException();
     if(s > v.length) {
       Object vnew[] = new Object[s];
       System.arraycopy(v, 0, vnew, 0, size);
       v = vnew;
     }
     else
       for(int i=s; i<size; i++)
         v[i] = null;
     size = s;
   }
La mia alternativa alloca un nuovo vettore
solo quando s > v.length.
Dal punto di vista della performance
   La tua proposta è + conveniente quando
          s non è troppo grande
        e s è molto minore di size.
   La mia proposta è + conveniente quando
          s è molto grande
   oppure s è poco minore di size.
   oppure s >= size && s <= v.length
Ma bisogna comunque ricordare che:
   "Premature optimization is the root of all evil."
- Dario