gpt4 book ai didi

java - 批量插入 MySQL 会导致 GC 开销和/或 Java 堆空间错误

转载 作者:行者123 更新时间:2023-11-29 17:46:52 28 4
gpt4 key购买 nike

我正在尝试一次性插入大约 190 万行作为批量插入到 MySQL 中。代码在 170 万行或更少的情况下工作得非常顺利,但对于超过 180 万行,我会遇到 GC 开销和/或有时出现 Java 堆空间错误。

代码:

    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() 方法有限制。每批处理的行数。我设置了autoCommit(FALSE),然后在执行PreparedStatement后commit()。

注意:我读过很多关于 GC 开销和 Java 堆错误的文章和帖子。任何关于为什么会发生这种情况的建议或指示都值得赞赏。

最佳答案

很有可能,您刚刚耗尽了内存。该消息具有误导性,因为高 GC 开销通常很简单,因为没有任何可收集的内容(所有内存都在使用中)。

批处理的原因是避免每个命令的高开销。就性能而言,如果您使用 1000 行或 1000000 行的批处理,这并不重要。因此尝试小批量。

如果您的应用程序可以忍受一段时间不完整的数据,也许还可以尝试较小的提交。

请注意,您将在内存中保存 triples 中的原始行和 tripleToInsert 中的拆分行。由于有 180 万行和总共 3 GB,每行可以使用的空间少于大约 1500 字节。考虑到一个字符在 Java 中是两个字节,考虑到您将其存储两次并且总是存在一些开销,因此它可以在每行 < 300 个字符的情况下工作(只是猜测)。

你基本上做得对,只是这么大的批处理需要大量的内存。如果这只是一个导入,那么您可以通过在消耗未分割的三元组时清除它们来节省一些内存。

有时可以使用数据库提供的内置 CSV 导入。

关于java - 批量插入 MySQL 会导致 GC 开销和/或 Java 堆空间错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49743152/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com