当使用CLOB插入大数据记录内容(450kb)时,它会导致内存不足错误。插入200次数据内容后会产生此错误。
下面是它的堆栈跟踪。
DBAppender::updateParameters()::Data.Length()::432164
Exception in thread "AppointmentFileListener" java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:2367)
at java.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:130)
at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:114)
at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:415)
at java.lang.StringBuffer.append(StringBuffer.java:237)
at java.io.StringWriter.write(StringWriter.java:101)
我尝试了所有可能的解决方案:
确保完成交易后所有结果集语句都已关闭。
使用setString(), setClob(), setASCIIStream()
设置CLOB值。
堆大小增加到1GB和2GB。
代码段
public class DBAppender extends AppenderSkeleton
{
private void initialize() throws ClassNotFoundException, SQLException
{
if (!EmbeddedDBManager.databaseExists())
{
EmbeddedDBManager.createDatabase();
}
openConnection();
thread = new WriteThread();
// start the thread
thread.start();
initialized = true;
}
class WriteThread extends Thread
{
final int MAX_UPDATE_ATTEMPTS = 100; // number of times to attempt connection to db
private volatile boolean stop = false;
public void stopProcessing()
{
stop = true;
}
@Override
public void run()
{
LoggingEvent event = null;
while (!stop)
{
try
{
event = buffer.take();
if (event != null)
{
int tries = 0;
while (!stop && tries < MAX_UPDATE_ATTEMPTS)
{
try
{
if (connection == null || connection.isClosed())
{
openConnection();
}
updateParameters(event);
statement.execute();
break;
}
catch (Exception e)
{
tries += 1;
if (tries < MAX_UPDATE_ATTEMPTS)
{
Thread.sleep(1000);
}
else
{
errorHandler.error("Failed to write event to database", e, ErrorCode.WRITE_FAILURE);
}
}
}
}
}
catch (Exception e)
{
errorHandler.error("Error in appender WriteThread", e, ErrorCode.FLUSH_FAILURE);
}
}
}
}
private void updateParameters(LoggingEvent event) throws SQLException
{
statement.clearParameters();
if (table.equalsIgnoreCase("tracemessages"))
{
String data = event.getRenderedMessage();
statement.setTimestamp(1, new Timestamp(event.getTimeStamp()));
statement.setLong(2, event.getTimeStamp());
statement.setString(3, Conversions.field(data, "|", 0));
statement.setString(4, Conversions.field(data, "|", 1));
String temp = data.substring(data.indexOf("|", data.indexOf("|") + 1) + 1);
if (temp.length() > 32600)
{
statement.setString(5, temp);
statement.setString(6, temp.substring(0, 32600));
}
else
{
statement.setString(5, null);
statement.setString(6, temp);
}
temp = null;
data = null;
}
}
private String getSQL()
{
StringBuilder sql = new StringBuilder();
sql.append("insert into ").append(table);
if (table.equalsIgnoreCase("traceevents"))
{
sql.append("(datetime, msecs, threadid, messageid, correlationid, eventtype, eventobject, entity, execkey, data, reference) values (?,?,?,?,?,?,?,?,?,?,?)");
}
else
{
sql.append("(datetime, msecs, reference, execkey, data, datapart) values (?,?,?,?,?,?)");
}
return sql.toString();
}
public void close()
{
thread.stopProcessing();
thread.interrupt();
closeConnection();
EmbeddedDBManager.removeShutdownListener(this);
this.closed = true;
}
protected void openConnection() throws ClassNotFoundException, SQLException
{
connection = EmbeddedDBManager.getConnection(EmbeddedDBManager.DEFAULT_DATABASENAME);
statement = connection.prepareStatement(getSQL());
}
}
对此有任何建议真的很感激。