批量批量插入MySQL会产生GC Overhead和/或Java Heap Space错误
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了批量批量插入MySQL会产生GC Overhead和/或Java Heap Space错误相关的知识,希望对你有一定的参考价值。
我试图一次插入大约190万行作为批量插入mysql。该代码的工作方式类似于1.7 mil或更少行的魅力,但我得到的GC Overhead和/或有时Java Heap Space错误超过1.8 Mil行。
码:
try {
// triples is of type ArrayList<String>
String[] tripleToInsert= null;
for (int i = 0; i < triples.size(); i++) {
count++;
tripleToInsert= triples.get(i).split("\s+");
/** Insert <s,p,o> into Triples table **/
preparedStmt.setString(1, tripleToInsert[0].trim());
preparedStmt.setString(2, tripleToInsert[1].trim());
preparedStmt.setString(3, tripleToInsert[2].trim());
preparedStmt.addBatch();
preparedStmt.clearParameters();
tripleToInsert=null;
}
}
catch(OutOfMemoryError e)
{
System.out.println("OOM error: IN LOADING TO DB function on loop count: " + count);
e.printStackTrace();
}
String preEndTime= new SimpleDateFormat("HH:mm:ss").format(Calendar.getInstance().getTime());
System.out.println("Preprocessing Ended:" + preEndTime);
//Insert start time
String startTime= new SimpleDateFormat("HH:mm:ss").format(Calendar.getInstance().getTime());
System.out.println("Insert Started:" + startTime);
// execute the prepared statement as a batch
long[] results = preparedStmt.executeLargeBatch();
System.out.println("Update Count size: "+ results.length);
//Insert end time
String endTime = new SimpleDateFormat("HH:mm:ss").format(Calendar.getInstance().getTime());
System.out.println("Insert Completed:" + endTime);
遇到错误:
OOM error: IN LOADING TO DB function on loop count: 1888076
java.lang.OutOfMemoryError: GC overhead limit exceeded
at com.mysql.jdbc.SingleByteCharsetConverter.toBytesWrapped(SingleByteCharsetConverter.java:230)
at com.mysql.jdbc.StringUtils.getBytesWrapped(StringUtils.java:652)
at com.mysql.jdbc.PreparedStatement.setString(PreparedStatement.java:4005)
at LoadNTriplesByScript.loadTriplesByBatches(LoadNTriplesByScript.java:282)
at LoadNTriplesByScript.insertNTriplesToDB(LoadNTriplesByScript.java:137)
at LoadNTriplesByScript.main(LoadNTriplesByScript.java:77)
Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
at java.lang.Object.clone(Native Method)
at java.util.TimeZone.clone(TimeZone.java:738)
at sun.util.calendar.ZoneInfo.clone(ZoneInfo.java:647)
at java.util.TimeZone.getDefault(TimeZone.java:625)
at java.text.SimpleDateFormat.initializeCalendar(SimpleDateFormat.java:657)
at java.text.SimpleDateFormat.<init>(SimpleDateFormat.java:601)
at java.text.SimpleDateFormat.<init>(SimpleDateFormat.java:580)
at LoadNTriplesByScript.loadTriplesByBatches(LoadNTriplesByScript.java:330)
at LoadNTriplesByScript.insertNTriplesToDB(LoadNTriplesByScript.java:137)
at LoadNTriplesByScript.main(LoadNTriplesByScript.java:77)
Eclipse版本:Oxygen.1a版本(4.7.1a)
Java堆大小:-Xms2048m -Xmx3072m
我不确定这是否是由字符串操作(split()方法)引起的,或者是否在PreparedStatement上有一个限制的addBatch()方法。每批行数。我在执行PreparedStatement后设置了autoCommit(FALSE)然后commit()。
注意:我已经阅读了大量关于GC Overhead和Java Heap Errors的文章广告帖子。关于为什么会发生这种情况的任何建议或指示都表示赞赏。
很有可能,你只是内存不足。该消息具有误导性,因为高GC开销通常很简单,因为没有任何东西要收集(所有内存都在使用中)。
批处理的原因是避免高命令开销。关于性能,如果您使用1000或1000000行的批次,这几乎不重要。所以尝试小批量。
如果您的应用程序可以暂时看到不完整的数据,也可以尝试较小的提交。
请注意,你要记住triples
中的原始行和tripleToInsert
中的split行。对于1.8M行和3 GB总计,每行可以使用少于约1500字节。考虑到一个字符在Java中是两个字节,考虑到你将它存储两次并且总是有一些开销,所以它可以用于每行<300个字符(只是一个猜测)。
你基本上做得对,只是这么大的批量需要大量的内存。如果这只是一个导入,那么你可以通过清除未分割的三元组来节省一些内存。
有时可以使用DB提供的内置CSV导入。
以上是关于批量批量插入MySQL会产生GC Overhead和/或Java Heap Space错误的主要内容,如果未能解决你的问题,请参考以下文章
Java HSQLDB - 批量插入:OutOfMemoryError:超出 GC 开销限制
MySQL AutoIncrement--PXC集群批量插入操作获取自增ID异常问题