Newsgroup: it.comp.java
Titolo: possibile bug java? esaurimento dei file descriptor

Salve, non so se a qualcuno di voi sia mai capitato questo problema, da me
e' perfettamente riproducibile.
Sto testando sotto linux 64bit col relativo jdk (jdk-6u12-linux-x64).
Se provate ad aprire delle socket, quello che succede e' che vengono
allocati dei file descriptor in "eccesso", che alla chiusura della socket
non vengono rilasciati. Se il processo gira per molto tempo (ed e' il mio
caso) arrivera' ad un punto in cui il s.o. non alloca piu' altri fd per lo
stesso processo, il quale si vede fallire tutte le operazioni (socket, file,
ecc) col messaggio too many open files.
Se volete fare un test, io mi sono scritto un programmino di poche righe:
- appena lanciato fa una sleep (per darmi il tempo di risalire alla lista
dei file aperti)
- poi apre una socket verso 
www.google.it
 e nuova sleep (per elencare di
nuovo i file aperti)
- poi la chiude e di nuovo sleep (altro elenco)
- esce
Il risultato, sorprendente (o preoccupante) e' questo, appena aperta la
socket, lsof mi elenca:
COMMAND   PID      FD   TYPE  DEVICE    NODE      NAME
java                  23653   4u     IPv6    4950630     TCP
myip:52964->wy-in-f147.google.com:http (ESTABLISHED)
java                  23653   5u     sock     0,5            4950628 can't
identify protocol
eccolo li', il fd 5... un tipo sock con misterioso can't identify protocol.
Chiusa la socket e rieseguito lsof, la connessione tcp (fd 4) e' sparita,
quella con 5 e' rimasta.
Finita l'esecuzione, tutti gli handle vengono correttamente rilasciati.
L'unico modo per non far morire brutalmente la mia applicazione e'
riavviarla almeno una volta a settimana, ma questo mi pare decisamente
assurdo.
Nessuno ha informazioni o consigli in merito? sotto altri sistemi o
piattaforme e' tutto a posto? A me pare un enorme leak per un qualche bug
della sun, ma prima di andare ad accusarli vorrei essere sicuro ^^;
Grazie
CarMas

Posso aggiungere anche uno strace della cosa:
24511 socket(PF_INET6, SOCK_STREAM, IPPROTO_IP) = 4
24511 connect(4, {sa_family=AF_INET6, sin6_port=htons(80),
inet_pton(AF_INET6, "::ffff:209.85.227.147", &sin6_addr), sin6_flowinfo=0,
sin6_scope_id=0}, 28 ) = 0
24511 dup2(5, 4)                        = 4
24511 close(4)
in cui si vede che tutto torna.
Chissa' perche' dopo aver creato la socket e fatto la connect, si inventa 
una dup.... il risultato e' che quel fd rimane pericolante per i fatti 
suoi...
Saluti
CarMas

 - esce
Come facciamo a fare dei test...se non fai vedere il tuo programmino? :)
(posso immaginarmi almeno una dozzina di errori nell'implementazione di 
quello che hai descritto)
Lucio
-- 
Lucio Benfante
JUG Padova           
http://www.parancoe.org
 ...have a look at it!
www.jugpadova.it
 
http://www.jugevents.org

 ecc) col messaggio too many open files.
Se non ricordo male, un errore del genere succede anche con diversi 
application server sotto linux.
Un workaround spiccio potrebbe essere quello di lavorare con il comando 
ulimit e, con qualcosa
del tipo ulimit -n 65000, spostare molto in alto l'asticella del numero 
massimo di file apribili.
Resta da vedere se questo comando viene "digerito" senza problemi o se 
occorre lavorare
anche su altri parametri etc; ma qui non so come aiutarti e chiederei a 
qualcuno che ne sa di pi�
di darci il suo parere....
Prima per� di toccare parametri del kernel in totale allegria, IMHO ti 
converrebbe verificare il comportamento
del programmino o del software che da' problemi... magari il bug � software, 
e non del JRE.
Ciao,
    Scorpio

 quello che hai descritto)
Oddio, non che ci voglia molto per scrivere questo programmino :P
 public static void main(String[] args) {
                try {
                        System.out.println("Avviato");
                        try { Thread.sleep(40000); }
                        catch(Exception ex) { }
                        Socket s=new Socket("
www.google.it
",80);
                        System.out.println("aperta: "+s.toString());
                        try { Thread.sleep(15000); }
                        catch(Exception ex) { }
                        s.close();
                        System.out.println("chiusa");
                        try { Thread.sleep(15000); }
                        catch(Exception ex) { }
                        System.out.println("fine");
                }
                catch(Exception e) {
                        e.printStackTrace();
                }
}
lsof non mente, dopo la println "chiusa" rimangono dei file descriptor 
aperti e non gestiti.
Il bug imho e' palese, se mi dici gli errori di implementazione posso 
ricredermi... ho avuto conferma da altre persone che devono riavviare 
regolarmente delle loro applicazioni server per questo motivo.
Questo e' molto simile
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6215050
non so con che coraggio lo segnino closed, c'e' tantissima gente che si 
lamenta dello stesso problema.
Saluti
CarMas

 massimo di file apribili.
Si' ho letto anch'io soluzioni di questo tipo.
Ma non vuol dire correggere il problema, vuol solo dire rimandarlo nel tempo 
e (almeno dal mio punto di vista) non e' una soluzione accettabile...
Saluti
CarMas

CarMas ha scritto:

Allora su opensuse 11.1 java 1.6.0
prima di avviare l'"applicativo" listato sopra:
lsof |wc -l 2327
all'apertura della socket:
lsof |wc -l 2736
alla chiusura della socket:
lsof |wc -l 2330
ovviamente ho controllato anche l'output di lsof, a me sinceramente
chiude i file correttamente.

Scusa perï¿œ io sono a 32 bit, sarï¿œ un problema dell'implementazione a 64bit?

CarMas ha scritto:

Leggendo un pï¿œ mi pare di capire che sia un problema relativo al garbage
collector che nel caso di un server a bassa latenza non viene mai
avviata la versione full, prova a fare cosi:
s.close();
s = null;
ogni tot richiama esplicitamente system.gc();
facci sapere...

 chiude i file correttamente.
Hai mica guardato solo il processo in questione? vuoi dire che da te non 
appare mai una cosa tipo "sock" con "can't identify protocol"?
Io intanto ho provato anche sotto una fedora7 a 32bit... ma anche li' mi fa 
lo stesso identico problema. Quindi escluderei la questione 32/64bit.
Poi ho provato a disabilitare ipv6, perche' in giro c'era chi diceva che 
anche quello potesse influire, ma nulla di risolto...
Continuano a rimanermi questi descriptor persi in giro :(
Saluti
CarMas 

 facci sapere...
Il gc e' una delle prime cose che sono state fatte... il server gira 
con -verbosegc ed infatti ogni tanto nella console si legge:
[Full GC (System) [PSYoungGen: 96K->0K(74624K)] [PSOldGen: 
40722K->40722K(118720K)] 40818K->40722K(193344K) [PSPermGen: 
29901K->29816K(30720K)], 0.1670820 secs] [Times: user=0.22 sys=0.00, 
real=0.17 secs]
Purtroppo il full gc gira, ma lsof aumenta sempre la lista delle socket 
"dimenticate aperte"...
Saluti
CarMas

 
cazzarola a me non appare nessun sock con can't identify protocol...
Quello che avevo letto io ï¿œ che la chiusura nel descrittore ï¿œ nel
finalize per questioni di performance quindi solo quando l'oggetto viene
realmente deallocato i file descriptor vengono chiusi, per questo avevo
suggerito di mettere il socket a null e chiamare il garbage collector
altro non so davvero che suggerire era un bug noto su linux e solaris ma
si parla del 2005 con le ultime versioni non dovrebbe succedere.

 ha scritto nel messaggio 
news:4a3f3bf6$0$843$4faf...@reader5.news.tin.it...

E' vero, non � una soluzione definitiva, diciamo che ti consente di campare
fintanto che non si trova una soluzione :-)
Scherzi a parte, la release del SO qual'� ?
Scorpio 

 Oddio, non che ci voglia molto per scrivere questo programmino :P
...lasciamo perdere...
Ho provato, e a me funziona regolarmente, non rimangono connessioni aperte:
java version "1.6.0_14"
Java(TM) SE Runtime Environment (build 1.6.0_14-b08)
Java HotSpot(TM) Server VM (build 14.0-b16, mixed mode)
Linux lalla 2.6.26-2-686 #1 SMP Thu Mar 26 01:08:11 UTC 2009 i686 GNU/Linux
Giusto per migliorare il codice, andrebbe scritto cosï¿œ (ma per un test 
va benissimo anche il tuo):
     public static void main(String[] args) {
         Socket s = null;
         try {
             System.out.println("Avviato");
             try { Thread.sleep(40000); } catch (Exception ex) { }
             s = new Socket("
www.google.it
", 80);
             System.out.println("aperta: " + s.toString());
             try { Thread.sleep(15000); } catch (Exception ex) { }
         } catch (Exception e) {
             e.printStackTrace();
         } finally {
             try {
                 if (s != null) {
                     s.close();
                     System.out.println("chiusa");
                 }
             } catch (IOException e) { }
             try { Thread.sleep(15000); } catch (Exception ex) { }
         }
         System.out.println("fine");
     }
Ciao


 Scherzi a parte, la release del SO qual'� ?
E' una CentOS 5:
Linux 2.6.18-92.1.22.el5xen #1 SMP Tue Dec 16 12:26:32 EST 2008 x86_64 
x86_64 x86_64 GNU/Linux
quanto a java:
java version "1.6.0_14"
Java(TM) SE Runtime Environment (build 1.6.0_14-b08)
Java HotSpot(TM) 64-Bit Server VM (build 14.0-b16, mixed mode)
Saluti
CarMas 


Hai provato su un'altra release di Linux ? Non vorrei sparare sul pianista,
ovviamente, ma se a parit� di JRE su una piattaforma c'� un problema e
su un'altra no, pu� anche darsi che ad avere qualche bug sia il sistema
operativo...hai scaricato tutti gli update per CentOS ?
Hai provato ad eseguire il codice che Lucio ha postato sul tuo sistema ?
Scorpio

 Hai provato ad eseguire il codice che Lucio ha postato sul tuo sistema ?
Chiaro, anche se mi sembravano soprattutto ottimizzazioni stilistiche ho 
provato... e non e' cambiato nulla, stesso risultato.
Grazie per i suggerimenti!
Saluti
CarMas

 provato... e non e' cambiato nulla, stesso risultato.
Sï¿œ, stilistiche per un test...ma in codice di produzione meglio che le 
usi, altrimenti la tua applicazione non durerï¿œ a lungo.
Tornando al problema, mi sembra di ricordare che Fedora, CentOS, ecc. 
abbiano di default abilitato SELinux, che a me ha sempre causato grossi 
grattacapi quando si trattava di installare applicazioni che avessero 
bisogno di servizi di rete. Magari non c'entra niente, ma provare a 
disabilitarlo per un test non costa nulla.
Purtroppo non saprei aiutarti piï¿œ di cosï¿œ, di solito uso Debian, e le 
mie esperienze con le altre distribuzioni sono molto limitate.
