在 Red Hat 上运行时 Java 内存泄漏,但在 Mac OS X 上没有内存泄漏

发布于 2024-10-05 12:13:46 字数 2006 浏览 3 评论 0原文

我有一个 java webobjects 应用程序,在 Red Hat 上运行时显示内存泄漏问题,但在 Mac OS X 上运行时没有出现此类问题。JVM 是相似的。

Mac OS X 10.6.5 使用 Apple 的 java 1.6.0_22 64 位 Red Hat EL 5.0 使用 Sun 的 java 1.6.0_20 64 位

我将其配置为在内存不足时执行堆转储,并使用 eclipse 内存分析器工具对此进行分析表明问题出在创建的代码的一部分中向 Web 服务发送 HTTP 请求的线程。创建线程的原因是为了对请求实现超时,因为Web服务有时不可用。

有人有什么想法吗?

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

编辑: 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.

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

朦胧时间 2024-10-12 12:13:46

我听说 WOHTTPConnection 已损坏,不应使用。 WOHTTPConnection 没有为您提供关闭连接的可靠方法。在其他方面它也是不可靠的。

解决方案是使用 Apache HttpComponents HttpClient 重写代码

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

芯好空 2024-10-12 12:13:46

我认为问题在于 Thread.interrupt 实际上并没有停止你的线程。如果线程正在运行,JVM 永远不会清理该线程。

我会向您的线程添加一个 closeConnection 方法,并尝试调用该方法来代替您的 Thread.interrupt 调用或除了您的 Thread.interrupt 调用之外调用该方法。您可能需要对其进行一些修改,但想法是显式停止保持线程运行的 IO:

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

}

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

}

缱绻入梦 2024-10-12 12:13:46

您需要关闭WOHTTPConnection句柄吗? (我不熟悉那个 API ...)。

跟进

检查后发现,connection.readResponse() 关闭了连接,因此我不需要手动执行此操作。

@Rudiger - 您假设对 connection.readResponse() 的调用总是成功。如果问题是抛出未报告的异常怎么办? (默认行为是默默地忽略子线程上引发的错误。)

我认为您应该在finally块中关闭连接句柄......以防万一。

或者更好的是,完全放弃WOHTTPConnection

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文