繁体   English   中英

打开文件过多错误

[英]Too many open files error

介绍

我已经在Web上找到了大量有关“ 打开文件过多”异常的信息,但是我无法解决这种奇怪的情况。 如我所读,当超过操作系统中定义的进程打开的文件描述符的数量时,将引发异常。 这些文件的性质是多种多样的。 文件可以是套接字,文档等。我发现了健壮和安全的方法来打开在Java应用程序中实现的文件。

该应用程序是一个简短程序,可使用Boilerpipe算法下载网页。 这样,我就可以得到该站点最具代表性的内容。 然后,以适当的格式( TREC格式 )将其写入磁盘。 这些网站的URL取自我使用JDBC连接器访问的MySQL数据库。

因此,我认为可以在三个不同的地方引发异常:

  • 连接数据库
  • 与网站的HTTP连接
  • 打开和写入文件

虽然,正如我所说,我认为我使用正确的方式打开和写入这些文件。

问题

有成千上万个URL需要处理,并且一段时间后会引发异常( 这也使得调试非常困难... )。 我不知道这是否重要,但是URL被分为不同的类别,并且我运行该程序的不同实例以加快整个过程。 类别不会重叠,因此应该没有任何问题。

为了使其更具可读性,我将仅简化代码的这三个部分:

  1. 数据库访问

     // Connect to database Connection dbconn = null; try { String dbUrl = "jdbc:mysql://" + dbServer + "/" + dbName; Class.forName ("com.mysql.jdbc.Driver").newInstance (); dbconn = DriverManager.getConnection(dbUrl, dbUser, dbPass); System.out.println ("Database connection established"); } catch (Exception e) { e.printStackTrace(); System.err.println ("Cannot connect to database server"); System.exit(-1); } System.out.println(" Downloading category: " + category); Statement s = null; try { s = dbconn.createStatement(); } catch (SQLException e) { System.err.println ("Error on creating the statement"); System.exit(-1); e.printStackTrace(); } String q = "SELECT resource,topic FROM " + "content_links " + "WHERE topic LIKE 'Top/" + category + "%';"; try { s.executeQuery(q); } catch(Exception e) { System.err.println ("Error on executing the SQL statement"); System.exit(-1); e.printStackTrace(); } ResultSet rs = null; try { rs = s.getResultSet (); } catch (SQLException e) { System.err.println ("Error on getting the result set"); System.exit(-1); e.printStackTrace(); } int count = 0, webError = 0; // work with the result set try { while (rs.next ()) { // MAIN LOOP } } catch (SQLException e) { System.err.println ("Error on getting next item"); System.exit(-1); e.printStackTrace(); } // Close connection to database if (dbconn != null) { try { dbconn.close (); System.out.println (" Database connection terminated"); } catch (Exception e) { /* ignore close errors */ } } 
  2. HTTP连接,提取站点的标题和样板过滤器

     try { String title = ""; org.jsoup.nodes.Document doc = Jsoup.connect(urlVal).get(); for (Element element : doc.select("*")) { if (element.tagName().equalsIgnoreCase("title")) { title = element.text(); } if (!element.hasText() && element.isBlock()) { element.remove(); } } String contents = ""; contents = NumWordsRulesExtractor.INSTANCE.getText(doc.text()); storeFile(id, urlVal, catVal, title, contents); } } catch (BoilerpipeProcessingException e) { System.err.println("Connection failed to: " + urlVal); } catch (MalformedURLException e1) { System.err.println("Malformed URL: " + urlVal); } catch(Exception e2) { System.err.println("Exception: " + e2.getMessage()); e2.getStackTrace(); } 
  3. 写文件

     private static void storeFile(String id, String url, String cat, String title, String contents) { BufferedWriter out = null; try { out = new BufferedWriter( new OutputStreamWriter( new FileOutputStream( new File(path + "/" + id + ".webtrec")),"UTF8")); // write in TREC format out.write("..."); } catch (IOException e) { System.err.println("Error: " + e.getMessage()); e.printStackTrace(); } finally { try { out.close(); } catch (IOException e) { System.err.println("Error: " + e.getMessage()); e.printStackTrace(); } } 

对。 您正在泄漏文件描述符。

在第一种情况下,您将打开数据库连接,而永远不会关闭它。 该连接通常将使用套接字或其他方式与数据库进行通信。 由于您不关闭连接,因此套接字不会被关闭,并且您将泄漏文件描述符。

在第二种情况下,我怀疑对 Jsoup.connect(urlVal)的调用正在打开一个连接,然后您将其关闭。 这将导致文件描述符泄漏。

更正Connection接口上没有close()方法。 看起来必须创建实际的连接,然后使用get方法在内部将其关闭。 假设是这样,在第二种情况下没有文件描述符泄漏。

第三种情况不泄漏文件描述符。 但是,如果无法打开文件,请执行out.close(); 语句将尝试在null上调用方法...并将抛出NPE。


解决的办法是找到所有的地方,在那里你打开文件,数据库连接,HTTP连接,并确保手柄始终关闭。

一种实现方法是将close()调用(或等效调用)放在finally块中...,但要确保不要意外地对null调用close()

另一种方法是使用Java 7“尝试使用资源”语法。 例如:

private static void storeFile(String id, String url, String cat, 
                              String title, String contents) {
    try (BufferedWriter out = new BufferedWriter(
                new OutputStreamWriter(
                new FileOutputStream(
                new File(path + "/" + id + ".webtrec")),"UTF8"))) {
        // write in TREC format
        out.write("...");
        out.close();
    } catch (IOException e) {
        System.err.println("Error: " + e.getMessage());
        e.printStackTrace();
    }
}

(但是请注意,Java 7语法只能与实现新的Closeable接口的资源一起使用。)

添加到斯蒂芬的全面分析。 我建议为数据库使用连接池,尽管正如Stephen所指出的那样,除非关闭这些连接,否则将耗尽连接池,但至少可以更容易地发现原因...

我没有看到任何证据,但是您应该使用某种线程池下载页面,这将有助于最大程度地利用系统资源。 一些执行者服务就足够了。 就像我说的那样,您可能已经在执行此操作,但是没有显示任何代码(或注释)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM