2010-12-01 32 views
3

J'ai une application webobjects java qui présente des problèmes de fuite de mémoire lors de l'exécution sur Red Hat mais nous n'avions pas de problèmes quand elle fonctionnait sous Mac OS X Les JVM sont similaires.Une fuite de mémoire Java lors de l'exécution sur Red Hat mais pas de fuite de mémoire sur Mac OS X

Mac OS X 10.6.5 en utilisant java 1.6.0_22 64 bits d'Apple Red Hat EL 5.0 en utilisant Java 1.6.0_20 64 bits de Sun

Je configuré pour faire une décharge de tas quand il a manqué de mémoire, et l'analyse avec l'outil eclipse memory analyseur suggère que le problème est dans une partie du code qui crée un thread qui envoie une requête HTTP à un service web. La raison de créer le thread est d'implémenter un délai d'attente sur la requête car le service Web n'est parfois pas disponible.

Quelqu'un a-t-il des idées?

WOHTTPConnection connection = new WOHTTPConnection(host, port); 
    WORequest request = new WORequest(strMethod, strQuery, strHttpVersion, nsdHeader, content, null); 

    WebServiceRequester theRequester = new WebServiceRequester(connection, request); 
    Thread requestThread = new Thread(theRequester); 
    requestThread.start(); 
    try { 
      requestThread.join(intTimeoutSend); //timeout in milliseconds = 10000 
      if (requestThread.isAlive()) { 
       requestThread.interrupt(); 
      } 
    } catch(InterruptedException e) { 

    } 
    requestThread = null; 
    if(!theRequester.getTfSent()) { 
      return null; 
    } 
    WOResponse response = connection.readResponse(); 

...

class WebServiceRequester implements Runnable { 

    private WORequest theRequest; 
    private WOHTTPConnection theConnection; 
    private boolean tfSent = false; 

    public WebServiceRequester(WOHTTPConnection c, WORequest r) { 
     theConnection = c; 
     theRequest = r; 
    } 

    public void run() { 
     tfSent = theConnection.sendRequest(theRequest); 
    } 

    public boolean getTfSent() { 
     return tfSent; 
    } 
} 

EDIT: Les noms de classe fuite tel que rapporté par l'outil d'analyse de la mémoire Eclipse:

1,296 instances of "java.lang.Thread", loaded by "<system class loader>" occupy 111,947,632 (43.21%) bytes. 
1,292 instances of "er.extensions.eof.ERXEC", loaded by "java.net.URLClassLoader @ 0x2aaab375b7c0" occupy 37,478,352 (14.46%) bytes. 
1,280 instances of "er.extensions.appserver.ERXRequest", loaded by "java.net.URLClassLoader @ 0x2aaab375b7c0" occupy 27,297,992 (10.54%) bytes. 
+0

Si vous vous débarrasser du fil et laisser fonctionner normalement, sera la fuite de mémoire s'en aller? Si non, alors ce n'est pas votre problème. –

+0

INSPECTÉ nah il ne va pas loin :( – Rudiger

+1

Quel est le nom de la classe fuite? –

Répondre

1

J'ai entendu que WOHTTPConnection est cassé et ne doit pas être utilisé. WOHTTPConnection ne vous donne pas un moyen fiable de fermer la connexion. Il est également peu fiable d'autres façons.

La solution consiste à réécrire le code en utilisant Apache HttpComponents HttpClient

1

Avez-vous besoin de fermer la poignée WOHTTPConnection? (Je ne suis pas familier avec cette API ...).

FOLLOWUP

Vérifié en elle, ressemble à la connection.readResponse() ferme la connexion, donc je ne pas besoin de le faire manuellement.

@Rudiger - vous en supposant que l'appel à connection.readResponse()toujours réussit. Que faire si le problème est qu'il lance une exception qui n'est pas signalée. (Le comportement par défaut est de silence ignorer les erreurs jetées sur les fils de l'enfant.)

Je pense que vous devriez fermer la poignée de connexion dans un bloc finally ... juste au cas où.

Ou mieux encore, un fossé entièrement WOHTTPConnection.

+0

Vérifié, il ressemble à la connection.readResponse() ferme la connexion, donc je n'ai pas besoin de le faire manuellement – Rudiger

1

Je pense que le problème est que Thread.interrupt ne s'arrête pas réellement votre fil. Et la JVM ne nettoiera jamais le thread si elle est en cours d'exécution.

Je voudrais ajouter une méthode CloseConnection à votre fil et essayer d'appeler au lieu ou en plus de votre appel Thread.interrupt. Vous devrez peut-être modifier un peu, mais l'idée est d'arrêter explicitement l'IO qui maintient le fil conducteur:

WOHTTPConnection connection = new WOHTTPConnection(host, port); 
WORequest request = new WORequest(strMethod, strQuery, strHttpVersion, nsdHeader, content, null); 

WebServiceRequester theRequester = new WebServiceRequester(connection, request); 
Thread requestThread = new Thread(theRequester); 
requestThread.start(); 
try { 
     requestThread.join(intTimeoutSend); //timeout in milliseconds = 10000 
     if (requestThread.isAlive()) { 
      requestThread.closeConnection(); 
      requestThread.interrupt(); 
     } 
} catch(InterruptedException e) { 

} 
requestThread = null; 
if(!theRequester.getTfSent()) { 
     return null; 
} 
WOResponse response = connection.readResponse(); 

...

class WebServiceRequester implements Runnable { 

    private WORequest theRequest; 
    private WOHTTPConnection theConnection; 
    private boolean tfSent = false; 

    public WebServiceRequester(WOHTTPConnection c, WORequest r) { 
     theConnection = c; 
     theRequest = r; 
    } 

    public void run() { 
     tfSent = theConnection.sendRequest(theRequest); 
    } 

    public boolean getTfSent() { 
     return tfSent; 
    } 

    public void closeConnection() { 
     this.theConnection.close(); 
    } 

}

+0

En regardant plus loin il y a un cas où la connexion peut rester ouverte, malheureusement, vous ne pouvez pas appeler la méthode pour fermer la connexion parce que son privé.Il y a un problème avec cette classe en général et ne devrait pas être utilisé. – Rudiger