[英]Too many open files error
介绍
我已经在Web上找到了大量有关“ 打开文件过多”异常的信息,但是我无法解决这种奇怪的情况。 如我所读,当超过操作系统中定义的进程打开的文件描述符的数量时,将引发异常。 这些文件的性质是多种多样的。 文件可以是套接字,文档等。我发现了健壮和安全的方法来打开在Java应用程序中实现的文件。
该应用程序是一个简短程序,可使用Boilerpipe算法下载网页。 这样,我就可以得到该站点最具代表性的内容。 然后,以适当的格式( TREC格式 )将其写入磁盘。 这些网站的URL取自我使用JDBC连接器访问的MySQL数据库。
因此,我认为可以在三个不同的地方引发异常:
虽然,正如我所说,我认为我使用正确的方式打开和写入这些文件。
问题
有成千上万个URL需要处理,并且一段时间后会引发异常( 这也使得调试非常困难... )。 我不知道这是否重要,但是URL被分为不同的类别,并且我运行该程序的不同实例以加快整个过程。 类别不会重叠,因此应该没有任何问题。
码
为了使其更具可读性,我将仅简化代码的这三个部分:
数据库访问
// 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 */ } }
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(); }
写文件
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.