java - 网络爬虫耗尽堆空间

标签 java garbage-collection out-of-memory

我编写了一个小型爬虫,发现它耗尽了堆空间(尽管我当前将列表中的 URL 数量限制为 300 个)。

通过 Java Memory Analytics,我发现消费者是 char[] (64MB 中的 45MB,或者如果我增加允许的大小,还会更多;它只是不断增长)。

分析器还为我提供了 char[] 的内容。它包含爬虫读取的 HTML 页面。

-Xmx[...]m 的不同设置进行更深入的分析我发现 Java 使用了几乎所有可用空间,然后得到 out of heap当我想下载 3MB 大小的图像时。

当我给 Java 16MB 时,它使用 14MB 并失败,当我给 Java 64MB 时,它使用 59MB 并在尝试下载大图像时失败。

阅读页面是用这段代码完成的(编辑并添加.close()):

private String readPage(Website url) throws CrawlerException {
    StringBuffer sourceCodeBuffer = new StringBuffer();
    try {
        URLConnection con = url.getUrl().openConnection();
        con.setConnectTimeout(2000);
        con.setReadTimeout(2000);

        BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream()));
        String strTemp = "";
        try {
            while(null != (strTemp = br.readLine())) {
                sourceCodeBuffer = sourceCodeBuffer.append(strTemp);
            }
        } finally {
            br.close();
        }
    } catch (IOException e) {
        throw new CrawlerException();
    }

    return sourceCodeBuffer.toString();
}

另一个函数在 while 循环中使用返回的字符串,但据我所知,一旦该字符串被下一页覆盖,该空间就应该被释放。

public void run() {
    boolean stop = false;

    while (stop == false) {
        try {
            Website nextPage = getNextPage();

            String source = visitAndReadPage(nextPage);
            List<Website> links = new LinkExtractor(nextPage).extract(source);
            List<Website> images = new ImageExtractor(nextPage).extract(source);

            // do something with links and images, source is not used anymore
        } catch (CrawlerException e) {
            logger.warning("could not crawl a url");
        }
    }
}

下面是分析器给我的输出示例。当我想查看这些char[]在哪里时仍然需要,但分析器无法判断。所以我想它们不再需要了,应该被垃圾收集。由于它总是略低于最大空间,Java 似乎也进行垃圾收集,但仅限于目前保持程序运行所需的垃圾收集(没有考虑可能会有大量输入) )。

另外,明确调用System.gc()每 5 秒甚至设置后 source = null;没有工作。

网站代码似乎只是以任何方式尽可能长地存储。

我在使用什么东西吗similar to ObjectOutputStream 这强制永久保留读取的字符串?或者Java怎么可能保留这些网站Stringschar[]数组这么长?

Class Name                                                                                                                                                                                                                                                                                   | Shallow Heap | Retained Heap | Percentage
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
char[60750] @ 0xb02c3ee0  <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title>Wallpaper Kostenlos - 77.777 E-Wallpapers: Widescreen, 3D, Handy, Sexy Frauen</title><link rel="shortcut icon" href="http://img.e-wallp...|      121.512 |       121.512 |      1,06%
char[60716] @ 0xb017c9b8  <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title>Wallpaper Kostenlos - 77.777 E-Wallpapers: Widescreen, 3D, Handy, Sexy Frauen</title><link rel="shortcut icon" href="http://img.e-wallp...|      121.448 |       121.448 |      1,06%
char[60686] @ 0xb01f3c88  <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title>Wallpaper Kostenlos - 77.777 E-Wallpapers: Widescreen, 3D, Handy, Sexy Frauen</title><link rel="shortcut icon" href="http://img.e-wallp...|      121.384 |       121.384 |      1,06%
char[60670] @ 0xb015ec48  <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title>Wallpaper Kostenlos - 77.777 E-Wallpapers: Widescreen, 3D, Handy, Sexy Frauen</title><link rel="shortcut icon" href="http://img.e-wallp...|      121.352 |       121.352 |      1,06%
char[60655] @ 0xb01d5d08  <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title>Wallpaper Kostenlos - 77.777 E-Wallpapers: Widescreen, 3D, Handy, Sexy Frauen</title><link rel="shortcut icon" href="http://img.e-wallp...|      121.328 |       121.328 |      1,06%
char[60651] @ 0xb009d9c0  <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title>Wallpaper Kostenlos - 77.777 E-Wallpapers: Widescreen, 3D, Handy, Sexy Frauen</title><link rel="shortcut icon" href="http://img.e-wallp...|      121.320 |       121.320 |      1,06%
char[60637] @ 0xb022f418  <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title>Wallpaper Kostenlos - 77.777 E-Wallpapers: Widescreen, 3D, Handy, Sexy Frauen</title><link rel="shortcut icon" href="http://img.e-wallp...|      121.288 |       121.288 |      1,06%

编辑

在使用更多内存进行测试后,我发现 dominator tree 中出现了这样的 URL。

Class Name                                                                                                                                                                                                                                                                                              | Shallow Heap | Retained Heap | Percentage

crawling.Website @ 0xa8d28cb0                                                                                                                                                                                                                                                                           |           16 |       759.776 |      0,15%
|- java.net.URL @ 0xa8d289c0  https://www.google.com/recaptcha/api/image?c=03AHJ_VuuT4CmbxjAoKzWEKOqLaTCyhT-89l3WOeVjekKWW81tdZsnCvpIrQ52aLTw92rP-EUP9ThnzwBwHcRLXG6A0Bpwu11cGttRAUtarmWXhdcTVRoUMLNnJNZeuuA7LedgfTou76nl8ULyuIR3tgo7_lQ21tzzBhpaTSqwYHWyuZGfuRK3z9pgmqRqvI7gE4_4lexjYbkpd62kN...       |           56 |       759.736 |      0,15%
|  |- char[379486] @ 0xa8c6f4f8  <!DOCTYPE html><html lang="en">  <head>  <meta charset="utf-8">  <meta http-equiv="X-UA-Compatible" content="IE=EmulateIE9">  <title>Google Accounts</title><style type="text/css">  html, body, div, h1, h2, h3, h4, h5, h6, p, img, dl,  dt, dd, ol, ul, li, t...    |      758.984 |       758.984 |      0,15%
|  |- java.lang.String @ 0xa8d28a40  /recaptcha/api/image?c=03AHJ_VuuT4CmbxjAoKzWEKOqLaTCyhT-89l3WOeVjekKWW81tdZsnCvpIrQ52aLTw92rP-EUP9ThnzwBwHcRLXG6A0Bpwu11cGttRAUtarmWXhdcTVRoUMLNnJNZeuuA7LedgfTou76nl8ULyuIR3tgo7_lQ21tzzBhpaTSqwYHWyuZGfuRK3z9pgmqRqvI7gE4_4lexjYbkpd62kNBZ7UIDccO5bx6TqFpf-7Sl...|           24 |           624 |      0,00%
|  |  '- char[293] @ 0xa8d28a58  /recaptcha/api/image?c=03AHJ_VuuT4CmbxjAoKzWEKOqLaTCyhT-89l3WOeVjekKWW81tdZsnCvpIrQ52aLTw92rP-EUP9ThnzwBwHcRLXG6A0Bpwu11cGttRAUtarmWXhdcTVRoUMLNnJNZeuuA7LedgfTou76nl8ULyuIR3tgo7_lQ21tzzBhpaTSqwYHWyuZGfuRK3z9pgmqRqvI7gE4_4lexjYbkpd62kNBZ7UIDccO5bx6TqFpf-7Sl...    |          600 |           600 |      0,00%
|  |- java.lang.String @ 0xa8d289f8  c=03AHJ_VuuT4CmbxjAoKzWEKOqLaTCyhT-89l3WOeVjekKWW81tdZsnCvpIrQ52aLTw92rP-EUP9ThnzwBwHcRLXG6A0Bpwu11cGttRAUtarmWXhdcTVRoUMLNnJNZeuuA7LedgfTou76nl8ULyuIR3tgo7_lQ21tzzBhpaTSqwYHWyuZGfuRK3z9pgmqRqvI7gE4_4lexjYbkpd62kNBZ7UIDccO5bx6TqFpf-7Sl6YmMgFC77kWZR7vvZIPkS...|           24 |            24 |      0,00%
|  |- java.lang.String @ 0xa8d28a10  www.google.com                                                                                                                                                                                                                                                     |           24 |            24 |      0,00%
|  |- java.lang.String @ 0xa8d28a28  /recaptcha/api/image                                                                                                                                                                                                                                               |           24 |            24 |      0,00%

从我的意图来看,我真的很想知道:为什么 java.net.URL 的 HTML 源代码部分是这样的? ?这是来 self 打开的 URLConnection 吗?

最佳答案

我首先会尝试在 readPage 方法末尾关闭阅读器和 URL 连接。最好将此逻辑放在 finally 子句中。

保持打开的连接将使用内存,并且根据内部情况,GC 可能无法回收它,即使您不再在代码中引用它

更新(基于评论):连接本身没有 close() 方法,当连接到它的所有读取器都关闭时,该连接将被关闭。

关于java - 网络爬虫耗尽堆空间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11564851/

相关文章:

java - 在父类和子类中创建相同的方法会提供一些奇怪的输出

java - 在没有 GSM 调制解调器的情况下使用 Java 发送短信

python - 如何在python中释放内存?

java - 如何解决 java.lang.OutOfMemoryError : Java heap space without increasing the heap memory size

java - 由于 "unable to create new native thread"导致 OutOfMemory 时的堆转储

c# - UnitTest 你如何组织你的测试文件?

java - 从内部类访问时,应该由 fxml 分配的字段抛出 NullPointerException - javaFX

java - 将对象指向空引用并重新分配内存或仅分配一次内存是否更有效?

java - 串行 GC 对远程应用程序的影响?

objective-c - 使用 NSImage 的垃圾收集崩溃