java mysql java.lang.OutOfMemoryError:java堆空间
我开发了一个网络刮板。Web scraper使用6个线程,每个线程打开一个网页,获取一篇文章的文本,然后(使用驱动程序)将文本的每个单词写入mysql数据库 在程序执行期间,我得到一个java mysql java.lang.OutOfMemoryError:java堆空间。我在Eclipse上安装了Memory Analyzer,发现问题是由mysql驱动程序连接引起的:当我运行这个程序时,5分钟后驱动程序占用的ram是6MB,5分钟后是200MB,5分钟后是500Mb,然后我得到java错误堆空间 我不明白为什么会这样 下面是我用于模型的代码(用于访问mysql数据库) 每个线程只需调用insertCat方法,并在数据库中插入一个带有类别的单词 Eclipse的内存分析器插件说:java mysql java.lang.OutOfMemoryError:java堆空间,java,mysql,eclipse,multithreading,Java,Mysql,Eclipse,Multithreading,我开发了一个网络刮板。Web scraper使用6个线程,每个线程打开一个网页,获取一篇文章的文本,然后(使用驱动程序)将文本的每个单词写入mysql数据库 在程序执行期间,我得到一个java mysql java.lang.OutOfMemoryError:java堆空间。我在Eclipse上安装了Memory Analyzer,发现问题是由mysql驱动程序连接引起的:当我运行这个程序时,5分钟后驱动程序占用的ram是6MB,5分钟后是200MB,5分钟后是500Mb,然后我得到java错误
该代码从不关闭与数据库的连接 尝试在
insertCat
方法中创建/关闭连接。应尽快获得并释放连接。连接只应在执行持久性操作所需的时间内打开
public class model {
public synchronized void insertCat(String parola, String categoria){
Connection connect = null;
try{
Class.forName("com.mysql.jdbc.Driver");
connect = DriverManager.getConnection("jdbc:mysql://localhost/system?user=keyword_tool&password=l0gripp0");
PreparedStatement statement = connect.prepareStatement("insert into sostantivi (nome, categoria) values (?, ?)");
statement.setString(1, parola);
statement.setString(2, categoria);
statement.executeUpdate();
statement.close();
} catch (Exception e){
//System.out.println(e);
}finally{
if(connect != null){
try {
connect.close();
} catch (Exception e) {
System.out.println(e);
}
}
}
}
}
如果您创建新模型而不销毁它,将创建一个新连接,地图中有2000000个模型,因此您将有2000000个连接
您应该将所有连接代码提取到连接管理器池中,然后自己管理连接 根据您的评论,您只创建了一个“模型”(这是一个坏的类名),并在6个线程中使用它 这并不是一个特别好的设计——它要么由于在单个DB连接上进行同步而限制了性能(当您可以在每个线程上使用一个连接时),要么会遇到潜在的并发问题/错误 我在堆转储中只看到一个
com.mysql.jdbc.JDBC4Connection
这可能是由于误导性的显示,或者(哪种理论符合您声称的“单一模型”方法)它充满了预先准备好的声明或其他东西
理论上,这些应该被缓存和重用——实际上,您遇到了一个问题。有三个步骤可以尝试:
这看起来像是预处理语句缓存的某种问题。除非您能在代码中发现PreparedStmt或ResultSet处理的其他错误(其前景并不明显),否则1)和2)最有可能提供解决方案/或特定的解决方法。您如何知道
closeDBConnection()
正在被调用?把一些日志放进去。由于您没有显示该代码,很可能是重复调用了model()
构造函数,但由于代码中的某些缺陷,连接被泄漏或未关闭。我将closeDbConnection()放在了抓取程序的末尾。我在主类中创建了一个模型,每个线程都使用该模型。在抓取了我需要的东西之后,我在单个模型上调用closeDBConnection。这是错误的吗?您在connect.close()上引入了一个潜在的NPE,您必须检查null。此外,关闭语句和结果集也是一种很好的做法,其顺序与获得它们的顺序相反,即使通常在关闭连接时自动关闭。忽略异常也不是一个好主意。一个显而易见的假设&跳转到的常见错误,但“Eclipse内存分析器”或“累积对象”堆报告显然不支持它——它们只表示一个JDBC4Connection实例。他在评论中还表示,他只创建了一个带有一个连接的“模型”,并分享了这一点。@ThomasW我不认为凯文声称存在多个连接实例,他只是说它没有关闭。在关闭连接时,从连接中获得的其他资源也应该被释放,因此我认为它应该解决语句堆积的问题。编辑后仍然不正确——尽快返回连接只有在连接被合并时才有助于提高性能。在没有池的情况下关闭和重新打开会给每条语句带来连接设置开销(非常昂贵)。@eis--Kevin很好,但这次他看到的是“明显的”问题,而不是“实际的”问题。他所宣称的是他所宣称的——而不是关于每一次stmt关闭连接的好处的一般性的空谈(这是不正确的)。开发人员需要解决“实际”问题,这就是为什么我的答案建议尝试关闭和重新打开——但只能每1000条语句一次。我还建议调查另外两个可能的领域。我的解决方案旨在解决/解决精确的问题,而不会造成不必要的性能损失。这很好。我使用了修复编号2),我的程序现在开始运行!!!Kevin的解决方案不好,因为我的性能急剧下降(在我可以每秒下载6页之前,我可以每秒下载0,5页,因为每次写操作打开和关闭连接都需要时间)。非常感谢。尽管JDBC驱动程序可能仍然存在缺陷。。如果您尝试其他版本,它可能会被修复。
public class model {
public synchronized void insertCat(String parola, String categoria){
Connection connect = null;
try{
Class.forName("com.mysql.jdbc.Driver");
connect = DriverManager.getConnection("jdbc:mysql://localhost/system?user=keyword_tool&password=l0gripp0");
PreparedStatement statement = connect.prepareStatement("insert into sostantivi (nome, categoria) values (?, ?)");
statement.setString(1, parola);
statement.setString(2, categoria);
statement.executeUpdate();
statement.close();
} catch (Exception e){
//System.out.println(e);
}finally{
if(connect != null){
try {
connect.close();
} catch (Exception e) {
System.out.println(e);
}
}
}
}
}