English 中文(简体)
Java memory leak when running on Red Hat but no memory leak on Mac OS X
原标题:

I have a java webobjects app which is showing memory leak problems when running on Red Hat but we had no such problems when it was running on Mac OS X. The JVMs are similar.

Mac OS X 10.6.5 using java 1.6.0_22 64 bit from Apple Red Hat EL 5.0 using java 1.6.0_20 64 bit from Sun

I configured it to do a heap dump when it ran out of memory, and analysing this with the eclipse memory analyzer tool suggests that the problem is in a part of the code which creates a thread which sends an HTTP Request to a web service. The reason for creating the thread is to implement a timeout on the request because the web service is sometimes not available.

Does anyone have any ideas?

    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: leaked class names as reported by eclipse memory analyzer tool:

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.
最佳回答

I have heard that WOHTTPConnection is broken and shouldn t be used. WOHTTPConnection does not give you a reliable way of closing the connection. It is also unreliable in other ways.

The solution is to rewrite the code using Apache HttpComponents HttpClient

问题回答

I think the problem is that Thread.interrupt does not actually stop your Thread. And the JVM will never clean up the thread if its running.

I would add a closeConnection method to your thread and try calling that instead of or in addition to your Thread.interrupt call. You might need to modify it a bit, but the idea is to explicitly stop the IO that is keeping the Thread running:

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();
    }

}

Do you need to close the WOHTTPConnection handle? (I m not familiar with that API ...).

FOLLOWUP

Checked into it, looks like the connection.readResponse() closes the connection so I don t need to do it manually.

@Rudiger - you are assuming that the call to connection.readResponse() always succeeds. What if the problem is that it is throwing an exception that is not getting reported. (The default behavior is to silently ignore errors thrown on child threads.)

I think you should close the connection handle in a finally block ... just in case.

Or better still, ditch WOHTTPConnection entirely.





相关问题
Spring Properties File

Hi have this j2ee web application developed using spring framework. I have a problem with rendering mnessages in nihongo characters from the properties file. I tried converting the file to ascii using ...

Logging a global ID in multiple components

I have a system which contains multiple applications connected together using JMS and Spring Integration. Messages get sent along a chain of applications. [App A] -> [App B] -> [App C] We set a ...

Java Library Size

If I m given two Java Libraries in Jar format, 1 having no bells and whistles, and the other having lots of them that will mostly go unused.... my question is: How will the larger, mostly unused ...

How to get the Array Class for a given Class in Java?

I have a Class variable that holds a certain type and I need to get a variable that holds the corresponding array class. The best I could come up with is this: Class arrayOfFooClass = java.lang....

SQLite , Derby vs file system

I m working on a Java desktop application that reads and writes from/to different files. I think a better solution would be to replace the file system by a SQLite database. How hard is it to migrate ...

热门标签