Newsgroup: it.comp.java
Titolo: Liste dinamiche e leak di memoria

Salve a tutti,
volevo porre una domanda relativa al GC. Supponiamo di avere  una banale 
lista dinamica, in cui ogni elemento memorizza un reference all'elemento 
successivo, e di avere un reference solo all'elemento di testa.Secondo voi, 
strutture dati come questa possono appesantire in qualche modo il meccanismo 
di gc, e creare leak di memoria, quando la lista di oggetti non č piů 
referenziabile ?
Grazie a tutti !
Scorpio. 

Non esiste il leak di memoria in Java, il GC porta via tutto. Da quanto mi
ricordo io il meccanismo di mark & sweep dovrebbe eliminare la lista in una
sola passata se perdi l'hook all'elemento di testa.
-- 
---
Francesco Galli / Cinghiale Mannaro
Personal: 
http://cinghialemannaro.splinder.com
TMS project: 
http://tms.inera.it

 sola passata se perdi l'hook all'elemento di testa.
Mille grazie, mi hai fugato un po' di dubbi....
Scorpio. 

 Non esiste il leak di memoria in Java, il GC porta via tutto. 
Non per contraddirti, ma solo per essere pignolo :))
In realtà si possono ottenere dei bei memory leak anche in java, se si
implementa male il metodo finalize degli oggetti.
ciao domenico

 implementa male il metodo finalize degli oggetti.
   Sarebbe interessante un esempio, dal momento che - a quanto ne so - il
mark & sweep e' immune anche da trucchetti come le liste circolari o simili.
Ingannare un garbage collector serio... come lo faresti?
FG


Ingannare il garbage collector non è un compito sicuramente facile, ma 
neppure impossibile.. più che altro potrebbero esserci problemi di 
deframmentazione eccessiva di memoria, cosicchè il sistema runtime non 
riesce ad allocare oggetti. Comunque non è qualcosa che si ottiene 
facilmente anche con cattive tecniche di programmazione, da quel che ho 
letto bisogna praticamente farlo apposta...
Scorpio. 

 Ingannare un garbage collector serio... come lo faresti?
Ovviamente io parlavo in generale della garbage collection in Java, non
relativamente alla prima domanda del thread.
Il fatto è che il metodo finalize ha alcune "piacevoli" caratteristiche
(dai JavaDoc):
The finalize method is never invoked more than once by a Java virtual
machine for any given object.
Any exception thrown by the finalize method causes the finalization of this
object to be halted, but is otherwise ignored. 
Quindi:
 - se nel finalize() si lancia un eccezione senza finally: oggetto non
finalizzato e quindi memory leak
 - se nel finalize() non si compie tutto al primo colpo, il metodo non
viene più richiamato per lo stesso oggetto
CI sono un paio di esempi di questo nel sito del JUG TO:
http://www.jugtorino.it/vqwiki/jsp/Wiki?CuriositaSulLinguaggioJava

Scusami, ma dubito che il GC chiami il metodo finalize, ma agisca
direttamente sullo heap. Per cui si, crei memori leak, ma poi alla fine il
GC sistema tutto comunque. O sbaglio?


 GC sistema tutto comunque. O sbaglio?
Che il gc agisca direttamente sullo heap non so (non credo, ma non ho
certezze in merito), invece che il gc chiami il metodo finalize di ogni
oggetto sono sicurissimo e certissimo.
Sempre da javadoc:
protected void finalize()
Called by the garbage collector on an object when garbage collection
determines that there are no more references to the object. A subclass
overrides the finalize method to dispose of system resources or to perform
other cleanup.
etc etc
Nota che sempre nei javadoc è specificato per la classe Object, finalize
non fa niente, semplicemente ritorna, ma deve essere inteso per rilasciare
risorse allocate dall'oggetto.
ciao domenico

Francesco Galli ha scritto:
[cut]
// Can you spot the "memory leak"?
public class Stack {
  private Object[] elements;
  private int size = 0;
  public Stack(int initialCapacity) {
    this.elements = new Object[initialCapacity];
  }
  public void push(Object e) {
    ensureCapacity();
    elements[size++] = e;
  }
  public Object pop() {
    if (size == 0)
      throw new EmptyStackException();
    return elements[--size];
  }
/**
* Ensure space for at least one more element, roughly
* doubling the capacity each time the array needs to grow.
*/
  private void ensureCapacity() {
    if (elements.length == size) {
      Object[] oldElements = elements;
      elements = new Object[2 * elements.length + 1];
      System.arraycopy(oldElements, 0, elements, 0, size);
    }
  }
} 
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

 non l'ho mai sovrascritto.
Perché non bisogna fare affidamento sul finalize? E' lì a bella posta per
essere usato (quando è necessario).
Esempio di utilizzo: 
Classi che utilizzano pool di thread o pool di connessioni a DB:
quando l'oggetto viene garbage collected, nel finalize si rilasciano i
thread o le connessioni al pool.
Oggetti che devono notificare che vengono garbage collector (es. per
svegliare dei thread)
etc.
ciao domenico

 }
   dove effettivamente elements perde ogni referenza, il che vuol dire che
appena arriva il GC lo sega... dove sta il memory leak?

 appena arriva il GC lo sega... dove sta il memory leak?
in pop()
uL


Toh, non l'avevo notata quella finezza del --size :) in realtà sarebbe
dovuto essere size--.
Non e' un memory leak neanche quello, pero'; perdi l'elemento, e' vero, ma
quando rimuovi elements dalla memoria mediante gc tutti gli elementi accanto
a quelli di cui ti è riuscito un pop vengono sganciati.


 etc.
Beh,
tipicamente esistono due usi per i finalizer, ed entrambi poco frequenti o
poco importanti:
1- come safety-net nel caso qualcuno non usi correttamente un oggetto, che
comunque dovrebbe prevedere degli espliciti metodi di rilascio risorse
2- per gestire oggetti non java e quindi non sensibili al GC, a meno che
questi non utilizzino risorse molto importanti
infatti il GC potrebbe essere chiamato anche dopo molto tempo che
l'oggetto non è più reachable, oltre a non propagare eccezioni, ecc.


 a quelli di cui ti è riuscito un pop vengono sganciati.
E' un memory leak (in senso lato), perchè ti stai gestendo la memoria. Il
Gc non può sapere che in una cella dell'array c'è qualcosa che non ti
interessa più, è una semantica implicita. Gli oggetti a cui fanno
riferimento i singoli elementi dell'array sono tutti in ogni caso reachable


 thread o le connessioni al pool.
Non sono assolutamente d'accordo. Proprio l'uso di finalize() per chiudere 
connessioni verso database
è assolutamente da evitare. Vedi ad esempio 
http://java.sun.com/developer/TechTips/2000/tt0124.html
Non so se con java 1.5 le cose siano cambiate, ma ne dubito molto.
Scorpio.

 riferimento i singoli elementi dell'array sono tutti in ogni caso
reachable
   E' memory leak in senso lato, ok, ma non in senso stretto: piu' che
memory leak e' cattiva programmazione oppure stupid programmer :)
   A differenza di un memory leak VERO, se fai girare quel codice N volte
con N sufficientemente alto non impalli la VM.

 con N sufficientemente alto non impalli la VM.
potresti avere un OutOfMemory, anche se č improbabile


 
ma, una volta perso il riferimento all'instanza di Stack, il GC, di 
conseguenza, non ripulisce gli oggetti dipendenti?
Se perdo il riferimento a Stack, non posso più neanche ottenere i 
riferimenti agli oggetti in esso contenuti
O no?

 O no?
Si, gli oggetti non reachable vengono ripuliti. Ma lo Stack maneggia la
sua memoria e i gli oggetti rimangono reachable. Non è un problema della
copia e del raddoppio di dimensioni!
