我正在写一个工具,用于将数据从旧模式转换到oracle数据库中的新模式。
在我的数据库中大约有20个表。它们中只有两个是大的,它们可能有400万条记录。其他的很小(可能是一万或十万)。
现在我用一个线程来连续处理所有的小表,把大表分成几个块,创建一些线程,用一个线程处理一块,每一块就是一百万条记录。
现在我遇到了一些问题。当我启动程序时,一切都很好。但是当我的程序在一段时间后运行时,我会得到一些错误信息:
Exception in thread "Thread-8" java.lang.OutOfMemoryError: GC overhead limit exceeded
at oracle.jdbc.driver.OracleBlobInputStream.needBytes(OracleBlobInputStream.java:168)
at oracle.jdbc.driver.OracleBufferedStream.readInternal(OracleBufferedStream.java:178)
at oracle.jdbc.driver.OracleBufferedStream.read(OracleBufferedStream.java:147)
at oracle.jdbc.driver.OracleBufferedStream.read(OracleBufferedStream.java:137)
at oracle.jdbc.driver.BlobAccessor.getBytes(BlobAccessor.java:249)
at oracle.jdbc.driver.OracleResultSetImpl.getBytes(OracleResultSetImpl.java:714)
at oracle.jdbc.driver.OracleResultSet.getBytes(OracleResultSet.java:1625)
at datatransfer.processor.CProcessor.write(CProcessor.java:111)
at datatransfer.processor.Processor.process(Processor.java:77)
at datatransfer.thread.CThread.run(CThread.java:37)我已经检查了我的程序,没有闭环,我真的关闭了statement和resultset。
每个Thread都有自己的Connection。
我如何检查我的程序占用内存的原因?有没有办法解决这个问题呢?
ResultSet rs = statement.executeQuery(sql);
int count = 0;
long start = System.currentTimeMillis();
while(rsSrc.next()){
preStatement.setString(1, rsSrc.getString(1));
preStatement.setString(2, rsSrc.getString(2));
preStatement.setString(3, rsSrc.getString(3));
preStatement.setString(4, rsSrc.getString(4));
preStatement.setString(5, rsSrc.getString(5));
preStatement.setString(6, rsSrc.getString(6));
preStatement.addBatch();
count++;
if (count % batchSize == 0){
preStatement.executeBatch();
preStatement.clearBatch();
}
}
preStatement.executeBatch();
preStatement.clearBatch();
writeConn.commit();
long end = System.currentTimeMillis();statement和preStatement是由不同的Connection创建的,一个是旧模式,另一个是新模式。
我的代码中有什么地方错了吗?
发布于 2014-11-20 16:03:05
尝试使用jvisualvm分析RAM中的实例/对象创建,它通常会立即告诉您是否存在泄漏。(这是图形用户界面,不要惊慌;-)
文档-> https://docs.oracle.com/javase/6/docs/technotes/tools/share/jvisualvm.html
它是一个分析器,所以它会告诉你你把时间花在了哪里,你有多少个类的实例,以及你的应用程序运行时发生了什么。
它默认安装在linux上的官方oracle jdk中!
如果内存使用率几乎不变,但在边缘,请尝试增加堆(例如-Xmx2G)
发布于 2016-07-14 23:16:54
在我的例子中,我不得不从Matlab向DB发出成百上千条INSERT语句。我还得到了GC开销异常:
java.sql.SQLException: java.lang.OutOfMemoryError: GC overhead limit exceeded我的解决方案是,每隔几千次(在本例中为2000次)插入快照关闭一次数据库连接,从Matlab工作区中删除并清除对象。当然,为了随后打开新的连接。
classdef MySqlService < handle
properties
db;
counter = 0;
dblimit = 0;
end
methods
function x = executeQuery(obj, query)
obj.counter = obj.counter + 1;
if (obj.counter > obj.dblimit + 2000)
obj.dblimit = obj.counter;
delete(obj.db);
clear obj.db;
import lib.queryMySQL.src.edu.stanford.covert.db.MySQLDatabase;
obj.db = MySQLDatabase('localhost:3306', 'fani_dev', 'root', 'dev1');
end
obj.db.prepareStatement(query);
x = obj.db.query();
end
function obj = MySqlService()
import lib.queryMySQL.src.edu.stanford.covert.db.MySQLDatabase;
obj.db = MySQLDatabase('localhost:3306', 'fani_dev', 'root', 'dev1');
end
end
end脚本现在可以正常工作了。此外,CPU工作负载和RAM使用率似乎也不错。
发布于 2014-11-20 16:18:30
这个问题的一种可能的解决方案是增加Eclipse可用的堆大小。您可以在打开位于eclipse安装文件夹中的eclipse.ini文件时执行此操作。
打开文件后,您可以添加-Xmx2048M,这将为您的Eclipse提供2 GB的堆。
这个解决方案取决于您的系统有多强大,以及您可以将整个堆的多少内容提供给Eclipse。
For more information click here...
处理这个问题的另一种方法是尝试处理大表的小块(块)。
如果你想找出更深层次的原因,你可以创建一个堆转储(或者几个堆转储),然后使用http://www.eclipse.org/mat/分析它。它是一个非常强大的工具。
https://stackoverflow.com/questions/27033954
复制相似问题