我正在运行一个小程序,处理数据库中大约215K的记录。这些记录包含JmlB用于编组和解组对象的xml。
我正在运行的程序试图找到由于遗留而无法解组的xml。每次我有unmarshal异常时,我都会在arraylist中保存包含xml的异常消息。最后,我想发送一封包含所有失败记录的邮件,并附带原因异常消息。所以我使用arraylist中的消息和StringBuilder来组成电子邮件正文。
然而,在大约75K失败的情况下,当我构建主体时,StringBuilder刚刚停止追加到for循环中的某个点并且线程被阻塞。我后来改变了我的方法,不再从异常消息中附加xml,但我仍然不清楚为什么它不起作用。
可能是VM内存不足,或者字符串只能达到一定的大小(我怀疑在64位时代肯定是这样)。有没有更好的方法可以解决这个问题?我打算将StringBuilder发送到我的服务而不是先将字符串保存在arraylist中,但那将是一个如此脏的界面:(
任何建筑见解都将受到赞赏。
EDIT 按照这里的要求,这不是火箭科学。假设失败列表包含大约75K个条目,每个条目包含一个xml的avg 500到1000行
private String createBodyMessage(List<String> failures) {
StringBuilder builder = new StringBuilder();
builder.append("Failed operations\n");
builder.append("=================\n\n");
for (String failure : failures) {
builder.append(failure);
builder.append("\n");
}
return builder.toString();
}
答案 0 :(得分:2)
您可能只是成功
int sizeEstimate = failures.size() * 20;
StringBuilder builder = new StringBuilder(sizeEstimate);
builder.append("Failed operations\n");
builder.append("=================\n\n");
while (!failures.isEmpty()) {
builder.append(failures.remove(0));
builder.append('\n');
}
这样做不会调整StringBuilder的内部缓冲区的大小,并且会消耗失败以减少内存。
如果文字太大,可能无法解决问题。
压缩附件是标准程序。
答案 1 :(得分:1)
StringBuffer 基于数组结构,数组中的最大单元格数为 2 ^ 31-1
达到这个大小通常会在Java 7上引发错误,但我不太确定
解决方法是在达到StringBuffer的固定大小之前将数据交换到文件
答案 2 :(得分:1)
可能是VM内存不足,
如果你填满了堆,你会得到OutOfMemoryError
例外。
或者字符串只能是一定的大小(我怀疑在64位时代肯定)。
实际上,是的。 Java String
或StringBuilder
最多可包含2 ^ 32-1个字符 1 。
有没有更好的方法可以解决这个问题?我打算将StringBuilder发送到我的服务,而不是先将字符串保存在arraylist中......
如果真正的问题是字符串的串联太大而无法保存在StringBuilder
中,那将无济于事。
实际上,更好的方法是将字符串流式传输到PipedOutputStream,然后使用相应的PipedInputStream构建一个MimeBodyPart,然后将其附加到电子邮件中。您也可以在流堆栈中包含压缩器。
但更好的方法不会尝试发送数十亿字节的错误数据作为电子邮件附件。将它们保存为可以提取(或其他)的文件如果电子邮件收件人想要它们。
1 - 令人惊讶的是,javadoc似乎没有明确说明这一点。但是,String.length()
返回int
,各种字符串操作方法使用int
参数来指定偏移量和长度。当然,String
和StringBuilder
的标准实现使用单个char[]
作为后备存储,并且JLS 和的数组限制为2 ^ 31-1个元素em> JVM规范。