HtmlUnit 关闭所有窗口内存泄漏

问题描述 投票:0回答:4

HtmlUnit 似乎不会关闭 Web 客户端中的窗口,从而造成内存泄漏。我正在尝试使用 HtmlUnit 获取页面并将其传递给 JSoup 进行解析。我知道 JSoup 可以连接到页面,但我需要使用这种方法,因为我需要在解析某些站点之前保持登录会话。

这是代码:

import java.io.IOException;
import java.net.MalformedURLException;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;

import com.gargoylesoftware.htmlunit.BrowserVersion;
import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.HtmlPage;

public class HtmlUnitLeakTest {

public static void main(String args[]) throws FailingHttpStatusCodeException, MalformedURLException, IOException{

        WebClient webClient = new WebClient(BrowserVersion.CHROME);
        webClient.getOptions().setPrintContentOnFailingStatusCode(false);
        webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);
        webClient.getOptions().setThrowExceptionOnScriptError(false);
        webClient.getOptions().setJavaScriptEnabled(true);
        webClient.getOptions().setCssEnabled(false);

        for(int i = 0; i < 500; i++){
            HtmlPage page = webClient.getPage("http://www.stackoverflow.com");
            Document doc = Jsoup.parse(page.asXml());
            webClient.closeAllWindows();
            System.out.println(i);
            if((i % 5 == 0)){
                System.out.println(i);
            }
        }
    }
}

当运行时,内存不断攀升,在我的调试屏幕中,我可以看到所有窗口仍然在 Web 客户端下引用并且没有关闭。

我已经看到了这段代码,应该关闭这些窗口:

List<WebWindow> windows = webclient.getWebWindows();
for (WebWindow ww : windows) {
    ww.getJobManager().removeAllJobs();
    ww.getJobManager().shutdown();
}
webclient.closeAllWindows();

但可惜事实并非如此,我仍然存在内存泄漏。

有人遇到过这个问题吗?

干杯

版本信息:

HtmlUnit 2.15

java version "1.7.0_51"

Java(TM) SE Runtime Environment (build 1.7.0_51-b13)

Java HotSpot(TM) 64-Bit Server VM (build 24.51-b03, mixed mode)
java memory-leaks htmlunit
4个回答
3
投票

我有一段与你的代码非常相似的代码,在过去的两天里我一直在努力解决这个问题。我尝试了他们在网上提到的所有内容,但找不到解决方案 - 直到我开始摆弄代码,突然,泄漏停止了。 我当时使用内存分析器工具,我的程序使用了 2GB 内存(我在 jvm 参数中将其设置为 java 堆),然后在 20 分钟后崩溃了。现在已经运行了1个小时,内存占用稳定在10mb。

我做了什么? 我已将 webClient 初始化放入 for 循环中:

public class HtmlUnitLeakTest {

   public static void main(String args[]) throws FailingHttpStatusCodeException, MalformedURLException, IOException{

    for(int i = 0; i < 500; i++){
    try{
        WebClient webClient = initializeClient();

        HtmlPage page = webClient.getPage("http://www.stackoverflow.com");
        Document doc = Jsoup.parse(page.asXml());
        webClient.closeAllWindows();
        System.out.println(i);
        if((i % 5 == 0)){
            System.out.println(i);
        }
    }finally {
            webClient.getCurrentWindow().getJobManager().removeAllJobs();
            webClient.close();
            System.gc();
            }
        }
    }

    private static WebClient initilizeCilent(){
    final WebClient webClient = new WebClient(BrowserVersion.CHROME);
    webClient.getOptions().setPrintContentOnFailingStatusCode(false);
    webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);
    webClient.getOptions().setThrowExceptionOnScriptError(false);
    webClient.getOptions().setJavaScriptEnabled(true);
    webClient.getOptions().setCssEnabled(false);

    return webClient;
    }
}

我知道这在理论上是错误的方法,但我非常想让它发挥作用,现在它做到了! 如果您已经用更好(正确)的方法解决了问题,请我也想知道!


0
投票
 /**
 * Returns an immutable list of open web windows (whether they are top level windows or not).
 * This is a snapshot; future changes are not reflected by this list.
 *
 * @return an immutable list of open web windows (whether they are top level windows or not)
 * @see #getWebWindowByName(String)
 * @see #getTopLevelWindows()
 */
public List<WebWindow> getWebWindows() {
    return Collections.unmodifiableList(new ArrayList<>(windows_));
}

0
投票

HTMLunit 2.15 中存在一个错误,一个

onunload
脚本导致 JS 引擎线程关闭后再次运行,然后又继续运行。

所以我建议升级到更新版本(现在是2.27)。

您也可以在关闭之前遍历所有窗口并删除

onunload
处理程序。

final List<WebWindow> windows = webClient.getWebWindows();
for (final WebWindow window : windows) {
    ...
}
webClient.closeAllWindows();

0
投票

我自己也遇到了同样的错误。在这个答案中找到了一段对我有帮助的代码。

以下是禁用 WebClient 存储历史记录并实际导致内存泄漏的相关代码:

try {
    final WebClient webClient = getWebClient();
    final List<WebWindow> webWindows = webClient.getWebWindows();
    History window = webWindows.get(0).getHistory();
    Field f = window.getClass().getDeclaredField("ignoreNewPages_"); //NoSuchFieldException
    f.setAccessible(true);
    ((ThreadLocal<Boolean>) f.get(window)).set(true);
} catch (Exception e) {
    e.printStackTrace();
    throw new AssertionError("Can't disable history");
}

再次感谢@Fluffy

© www.soinside.com 2019 - 2024. All rights reserved.