数据库连接和OutOfMemoryError:Java堆空间

去年夏天,我创建了一个Java应用程序,它可以解析一些PDF文件并获取它们包含的信息,以便将它们存储在SQLite数据库中。

一切都很好,我每周都会不断添加新文件到数据库,没有任何问题。

现在,我正在努力提高我的应用程序的速度,我想看看如果我解析过去两年在新数据库中拥有的所有文件,它会如何。 那是我开始收到此错误的时候: OutOfMemoryError:Java堆空间 。 我以前没有得到它,因为我每周只解析大约25个新文件,但似乎一个接一个地解析1000多个文件要求更高。

我部分地解决了这个问题:我确保在每次调用数据库后关闭我的连接并且错误消失了,但代价很高。 解析文件现在难以忍受。 至于我的ResultSet和Statements / PreparedStatements,我已经在每次通话后关闭它们。

我想当我应该关闭我的连接以及何时应该继续使用相同的连接时,我有些不明白的事情。 我认为自从自动提交打开后,它会在每个事务(选择,更新,插入等)之后提交,并且连接会释放它正在使用的额外内存。 我可能错了,因为当我解析太多文件时,我最终得到了我提到的错误。

一个简单的解决方案是在每次x调用后关闭它,但是我再也不会理解为什么,我可能会在以后遇到相同的错误。 任何人都可以解释我什么时候应该关闭我的联系(如果完成的话除外) 如果我只是在我完成时应该这样做,那么有人可以解释我应该如何避免这个错误吗?

顺便说一下,我没有把它标记为SQLite,因为当我尝试在我的在线MySQL数据库上运行我的程序时遇到了同样的错误。

编辑正如Deco和Mavrav所指出的那样,问题可能不是我的连接。 也许这是文件,所以我将发布用于调用函数的代码逐个解析文件:

public static void visitAllDirsAndFiles(File dir){ if (dir.isDirectory()){ String[] children = dir.list(); for (int i = 0; i < children.length; i++){ visitAllDirsAndFiles(new File(dir, children[i])); } } else{ try{ // System.out.println("File: " + dir); BowlingFilesReader.readFile(dir, playersDatabase); } catch (Exception exc){ System.out.println("Other exception in file: " + dir); } } } 

因此,如果我使用目录调用该方法,它会使用我刚创建的File对象再次递归调用该函数。 我的方法然后检测到它是一个文件并调用BowlingFilesReader.readFile(dir,playersDatabase);

我认为方法完成后应该释放内存?

你对开放结果集和连接的第一直觉是好的,尽管可能不完全是原因。 让我们先从您的数据库连接开始。

数据库

尝试使用数据库连接池库,例如Apache Commons DBCP(BasicDataSource是一个很好的起点): http : //commons.apache.org/dbcp/您仍然需要关闭数据库对象,但这将保持不变在数据库前面顺利运行的东西。


JVM内存

增加为JVM提供的内存大小。 您可以通过添加-Xmx和之后的内存量来实现,例如:

  • -Xmx64m < - 这将为JVM提供64兆内存
  • -Xmx512m < - 512 megs

但要小心你的数字,在JVM上投入更多内存不会修复内存泄漏。 您可以使用JConsole或JVisualVM(包含在JDK的bin /文件夹中)来观察您使用的内存量。

穿线

假设您正在执行的解析这些记录的操作是可线程的,您可以通过将它们线程化来提高操作的速度。 但回答这个问题可能需要更多信息。

希望这可以帮助。

正如Garbage colleciton所发生的那样,我不认为内存会立即被重新收集用于后续进程和线程。所以我们不能完全把我们的鸡蛋放在那个篮子里。首先把所有文件放在一个目录中,而不是放在子目录中家长。 然后通过迭代这样逐个加载文件

 File f = null; for (int i = 0; i < children.length; i++){ f = new File(dir, children[i]); BowlingFilesReader.readFile(f, playersDatabase); f = null; } 

因此,我们使引用无效,以便释放文件对象,并在随后的GC中获取。 并检查限制测试它通过增加否。 文件以100,200开始.....然后我们将知道OME在什么时候被抛出。 希望这可以帮助。