Newsgroup: it.comp.java
Titolo: new && Garbage Collection

Ciao a tutti,
ho il seguente pezzo di codice che produce una DubbioMoltoGrosso Exception
:)
PrintWriter out;
while(iter.hasNext()) { /*Iter e' un iteratore di un Set*/
        tempUser = (Object) iter.next();
        out = new PrintWriter(tempUser.getSocket().getOutputStream(), true);
        out.println("BlaBla");
}
Quello che vorrei sapere e' se, facendo + volte 'new' sullo stesso oggetto,
quelli precedenti spariscono o mi creano Garbage.
Mi spiego meglio...
Se il ciclo si compie 10 volte, in memoria avro' 10 PrintWriter o uno solo?
Appena esco dallo scope del ciclo tutto sparisce comunque, vero?
Secondo voi e' una soluzione decente?
Scusate la tempesta di domande, sono un novellino Java con troooooppi dubbi
a riguardo!
Ciao!
Corrado
-- 
FrEe ThE kNoWlEdGe

 ha scritto nel messaggio
news:bct9i1$rg3$2...@lacerta.tiscalinet.it...


         true);
Out e` semplicemente un "ref", un riferimento all'oggetto vero e proprio
(se fossimo in C lo chiameremmo puntatore), quando il numero di ref che
referenziano un oggetto diviene 0 l'oggetto diviene passibile di garbage
collection (quindi resta in memoria fino a quando il garbage collector non
fa "pulizie"). ;)
Se devi ripetere piu` volte la scrittura sulle socket ti conviene creare i
PrintWriter una volta sola e ciclare direttamente su questi.
Ciao,
Marco
-- 
//\/\ Marco (LM) Lamberto
      e-mail:            
marcol...@despammed.com
      SIForge.org     -  
http://www.siforge.org/

 vari è naturale. Poi gradualmente non ci si fà più caso.
Eh, fino al momento in cui devi fare un'applicazione ad alte performance, e
ti accorgi di come sia importante farci caso! Sennò finiscono per avere
ragione i detrattori di java, quelli che cianciano di cose tipo "java è
lento"! ;)

Sono d'accordo con te.
Cosa ne pensi cmq del mio problemino?
Dovrei cambiare strategia? (magari quella che mi ha consigliato Marco).
Quel ciclo non si ripete 10 volte ma 100 o magari 1000...
Grazie


Beh veramente io in java faccio programmi scalari ad elevate performance
(Non sono comunque Time Critical). Sarà che dopo anni di programmazione le
cose le scrivo bene per abitudine, ma in java ti posso giurare che mi è
capitato una sola vlta di utilizzare StringBuffer per esempio. Eppure i miei
programmi girano veloci eccome.
Per quanto riguarda la filosofia se Sun voleva un ottimizzazione delle
performance al GC non ci pensava neppure.
Tendenzialmente poi preferisco programmi leggibili, flessibili e di facile
manutenzione a programmi ultraperformanti ma illeggibili.
Fra l'altro l'idea stessa di programmazione ad oggetti è, di per se, un
andare contro alle performance pure. Più classi fai più overhead aggiungi
non ci si può fare molto. Chiaro che la creazione non necessaria di istanze
nuoce alle performance, ma è abbastanza scontato. In un programmino come
quello dell'esempio ogni ottimizzazione a mio avviso è vana e serve solo a
vantarsi per aver ottimizzato.
Poi ci sono le ottimizzazioni nascoste del compilatore, le differenze nelle
implementazioni delle VM e tante altre cose.
Infine, come sai, sono punti di vista...
Ciao
"Immanuel" <Immanue...@TOGLIMInightly.com> ha scritto nel messaggio
news:bd564p$46n$1...@lacerta.tiscalinet.it...


 ha scritto nel messaggio
news:bd59nt$5gj$1...@lacerta.tiscalinet.it...


 vantarsi per aver ottimizzato.
Ed è proprio qui, che ti sbagli. Perché guarda cos'aveva scritto, lui:
PrintWriter out;
while(iter.hasNext()) { /*Iter e' un iteratore di un Set*/
        tempUser = (Object) iter.next();
        out = new PrintWriter(tempUser.getSocket().getOutputStream(), true);
        out.println("BlaBla");
}
cos'è secondo te, questo? Tu lo chiami un programmino, ma a me invece appare
evidente che questo è il ciclo di uscita di un sistema che propaga dei dati
in push, probabilmente di un sistema di chat. E' proprio in sistemi di
questo tipo, che è VITALE risparmiare oggetti, perché se non lo fai, con il
crescere degli utenti collegati, ed il crescere del tuo traffico, finisci
per esplodere. Ora, io non mi ricordo come sia fatto "dentro" il
PrintWriter, ma di certo so che al crescere degli eventi, questa roba genera
una serie di oggetti inutili, in particolare un PrintWriter per client per
evento, questo è totalmetne folle. Considerato che il ciclo di distribuzione
è single-thread (scelta probabilmente da rivedere...), si può sicuramente
creare perlomeno un PrintWriter per client MA NON PER EVENTO, e questo già
riduce drammaticamente la creazione degli oggetti inutili. Se poi consideri
che, appunto, in un sistema single threaded puoi tranquillamente
riutilizzare il PrintWriter (ammesso che consenta in qualche modo di
sostituire l'outputStream sottostante, perlomeno sottoclassando il
PrintWriter), usando un solo printwriter ottieni lo stesso risultato, e
senza la creazione inutile di un printwriter per evento per cliente. Ti pare
poco? No di certo, è di una serie di operazioni di questo tipo, che sono
fatte le ottimizzazioni dei programmi in java, ed è non attenendosi a queste
regole, che si finisce per fare della roba che non scala.


 Quel ciclo non si ripete 10 volte ma 100 o magari 1000...
Dunque, devi pensare due cose:
1) c'è un problema di oggetti creati inutilmente: mi sembra di intuire che
stai cercando di fare un sistema di chat (perlomeno il frammento di codice
che hai postato è un "pattern" di propagazione di un dato a una serie di
clienti collegati via socket, e se tanto mi dà tanto...).
2) c'è un problema di frequenza dell'aggiornamento, e di scrittura di rete:
stai facendo una cosa che scrive su centinaia di socket con un singolo
thread: questo fa un uso estremamente povero della CPU, perché le operazioni
di scrittura su socket sono operazioni di input/output "lente", che se fatte
da un thread singolo gli fanno perdere un sacco di tempo in attesa. In
questo modo, l'ultimo dei tuoi client non vede arrivare il suo evento che
dopo che tutte le letture-scritture degli altri sono avvenute, e questo è
estremamente poco ottimale, in questo tipo di applicazioni.
Le soluzioni sono:
1) come ho scritto nell'altro messaggio del thread, cercare di riutilizzare
il più possibile tutti gli oggetti che vengono creati e utilizzati lungo la
catena di distribuzione degli eventi. Ogni "new" che fai per portare un
evento (che sia una stringa che contiene un messaggio di chat, o qualsiasi
altra cosa!) dal punto di partenza al punto di arrivo, ti deve pesare come
se stessi facendo un affronto a tua madre! Quindi, NON creare un PrintWriter
per ogni evento e per ogni client, cerca di utilizzarne il meno possibile,
presumibilmente uno per client in virtù del punto 2).
2) utilizza più thread!!! Non puoi lasciare che il ciclo di distribuzione
degli eventi venga rallentato da tutte le operazioni sequenziali di
input-output. Qui hai almeno due possibilità:
2.1) usi un thread per ogni client connesso, dal ciclo principale non fai
altro che "inviare" l'evento ad ognuno dei thread (che lo riceverà tramite
una coda), il quale lo estrae dalla coda, e nel suo tempo di esecuzione lo
scrive sul socket, mentre il ciclo di distribuzione è libero di spedire
l'evento agli altri thread senza dovere aspettare che l'invio sia terminato.
Questo approccio ha il problema di richiedere un thread per client, e tende
a non scalare oltre qualche centinaio di client. Nelle ultime versioni di
Solaris e-o Linux questo non crea problemi per un po' (direi sui 500-600
thread, per una macchina abbastanza potente), ma da lì in poi comincerei a
vederla brutta
2.2) usi un thread pool più limitato, e le nuove api java.nio che non
forzano ad avere un thread per client: questa è la strada che seguiremo noi
(anche se per ora abbiamo un carico di meno di 1000 utenti fissi, e
riusciamo a gestirlo bene con le nostre macchine). Se ti interessano queste
cose, cerca il progetto SEDA di Matt Welsh, è basato su un sistema di
distribuzione ad eventi fra stadi diversi di trattamento che cerca di
massimizzare il throughput tramite un meccanismo adattativo, e sfrutta
concetti come quelli alla base delle nuove librerie di input-output di java.

 evento, questo è totalmetne folle.
Vero quello che scrivi: ma allora perchè non scrivere direttamente
sull'OutputStream? Risparmi qualsiasi new e non ti trovi nella situazione di
dover memorizzare riferimenti che possono invalidarsi in qualunque momento.
Ciao,
Ivan
"Immanuel" <Immanue...@TOGLIMInightly.com> ha scritto nel messaggio
news:bdd54t$qov$1...@lacerta.tiscalinet.it...


 queste regole, che si finisce per fare della roba che non scala.
+1
-- 
Fighting for peace is like fucking for virginity
ObjectZone - 
http://space.tin.it/computer/csadun

Caspita grazie, non potevo sperare in una risposta migliore, almeno adesso so
dove/come mettere le mani.
Cmq hai ragione, sto cercando di fare un sistema p2p. Non programmo da molto in
Java e forse ho un po troppe pretese, ma cmq imparare a fare le cose bene fin
da subito non fa di certo male.
Cerchero' di mettere a posto tutto appena avro' finito di mettere a posto
l'interfaccia! E dopo di questo dovro' capire come mandare i file... e dopo di
questo... mi sta passando la voglia (visto che lo faccio solo x imparare...) ;)
Semmai, tra un po di tempo, ri-posto e vi dico come procede la cosa. (Mi illudo
che ve ne freghi qlcs!!).
Grazie a tutti x i preziosi consigli!


 dover memorizzare riferimenti che possono invalidarsi in qualunque momento.
Beh, non si possono invalidare se tu non lo fai!! In altre parole, devi
avere
sotto controllo la tua applicazione, la struttura dei thead, ecc. Il
printwriter
in quel caso gli serviva probabilmente per sparare fuori dei dati
testuali, ma
era un caso particolare che poteva andar bene per illustrare la
questione piů
generale: nella catena di trattamento di un tick, devi risparmiare! ;)
-- 
Posted via Mailgate.ORG Server - 
http://www.Mailgate.ORG

Ciao! Spero che leggiate il mio messaggio, ormai e' un po che non posto su
questo thread.
Piccola premessa: scrivo per avere vostre opinioni sul modo che dovrei adottare
per fare un mio programmino, con queste caratteristiche:
1 Assolutamente inutile
2 Scemo
3 Esiste solo xche' voglio imparare il linguaggio
Quindi, per favore, se leggendo questo post noterete cose ASSURDE che vi faranno
venir voglia di vomitare, ignorate tutto quanto please!
Se invece avrete la voglia di rispondermi, sappiate che vi dovrete armare di
molta pazienza.
Uomo avvisato... ;)
Ok, inziamo...
Ho letto attentamente i vostri consigli.
Mi sono soffermato soprattutto su quello che aveva scritto Immanuel riguardo al
metodo di "spedizione" da implementare.
Tu mi hai consigliato di usare un thread per ogni client, e questo lo avevo
fatto fin da subito.
Inizialmente il codice per la spedizione era qello che vi ho postato. Un thread
usava un metodo della classe atta a contenere i dati utente (quindi anche i
socket) che scorreva i socket e creava per ognuno di essi un PrintWriter.
Questa soluzione non mi e' piaciuta fin da subito. Vi posto la situazione
attuale del mio "programmino" (Ivan fa bene a definirlo tale!).
Il main crea una Gui (Frame) a se stante. Il costruttore si preoccupa SOLTANTO
di creare l'interfaccia, mettere 2 actionListener qua e la e BASTA. Stop. Muore
li. I campi pero' (bottoni, textArea, ecc...) sono campi statici in modo da
essere accessibili dal GuiModifier, classe completamente statica che ha il
compito di gestire gli elementi della Gui. Tutte le altre classi del mio
programmino usano i metodi di questa classe x scrivere sulla textArea o x qls
altra operazione debbano fare sulla Gui. I metodi, ovviamente, sono
synchronized.
Il main, oltre al Frame, crea un ConnectionHandler, un ciclo che (ma guarda un
po'!) cicla all'infinito in attesa di connessioni. Quando ne riceve una, crea
un thread, e da quel momento tutto il compito sara' svolto dal thread.
I dati utente (socket, userId, ecc...) sono all'interno di una hashMap.
Questa hashMap e' definita static (ne voglio solo una, chiaramente) all'interno
di una classe che fornisce tutti i metodi necessari per accedere alla mappa. I
metodi sono synchronized e static (alcuni).
Vi propongo uno schemino:
                  MAIN
                   /\
                  /  \                    |-------|
                 /    \                   | Users |
                /      \               /->|  Map  |
            |-----|    |----------|    |  |-------|
         /->|Frame|    |Connection|    |  (Static)
         |  |-----|    | Handler  |    |
         |  (Staitc)   |----------|    |
         |            /      \  \  \   |
       |-------------|<------ t  t  t--/ (threads)
       | GuiModifier |        |  |  |
       |-------------|        |  |  |
          (Static)            c  c  c    (clients)
(Spero che il disegno si veda anche sui vostri reader...
Con l'opzione "rimuovi spazi in eccesso" si incasina tutto.
Al massimo, salvate il disegnino e guardatelo da console, ma non sono di certo
io che devo darvi le dritte!)
Ora... quando un thread (di quelli che parlano con l'utente) riceve una stringa,
dovrebbe scorrere la mappa, prendere i socket degli utenti e spedire il
messaggio a tutti. Tralasciando cose tipo "deve capire se l'utente fa parte
dello stesso canale" che sono di facile soluzione, quello che mi rende
perplesso e'... come faccio ad ottenere una lista di socket validi senza che il
thread si blocchi x un tempo eccessivo?
Possibile soluzioni a cui ho pensato:
quando un thread riceve una stringa, crea un thread che accede alla mappa, si fa
tornare un array di socket e manda a tutti il messaggio.
        Cosa accade? Il metodo che scorre la mappa e' perennemente al lavoro, e
rallenta gli altri thread.
Allora, faccio creare un thread al metodo che scorre la mappa. In questo modo
tutti i thread "utente" potranno accedere al metodo senza troppe storie.
Faccio un esempio
Class UserMap implements Runnable {
private static userMap = new HashMap();
public void sendToAll(String messaggio) {
 
   Thread t = new Thread(this)
   t.start();
 
}
public void run() {
   PrintWriter out;
   while(iter.hasNext()) { //Immaginiamo che ho creato l'iteratore
     out = new PrintWriter(iter.next().getSocket().getOutputStream(), true));
     out.println(messaggio);
   }
}
}
Zac! Si ripresenta il problema originale (sempre che questa soluzione sia
accettabile).
Come faccio a dire ad un PrintWriter (ma e' l'unico modo di scrivere sui
socket?!?!?) di cambiare socket su cui scrivere, senza ricorrere a new???
Ok direi basta, non ho piu' voglia di scrivere, spero che qlcn abbia la pazienza
di rispondermi.
Ringrazio anticipatamente chi porra' fine ai miei dubbi sull'argomento e a tutti
coloro che mi diranno le ca***te piu' grosse che ho commesso.
Gradirei, e forse e' la cosa che gradirei di piu', che qlcn mi dicesse se, come
approccio (il fatto che ci sia un oggetto che gestisce le modifiche alla gui,
ecc...) puo' andare.
Scusate, ma sono un novellino che ha sempre voglia di migliorare le cose!
Grazie && Ciao!



 Newsgroups: it.comp.java
 Sent: Sunday, June 29, 2003 5:56 PM
 Subject: Re: new && Garbage Collection [LUNGO]
 
 
 Ciao! Spero che leggiate il mio messaggio, ormai e' un po che non posto su
 questo thread.
 [...]
 
--------------------------------
Inviato via 
http://usenet.libero.it

 >Come faccio a dire ad un PrintWriter (ma e' l'unico modo di scrivere sui
 >socket?!?!?) di cambiare socket su cui scrivere, senza ricorrere a new???
 

 Ciao! Spero che leggiate il mio messaggio, ormai e' un po che non posto su
 questo thread.
