执行 JAVA 映射时出现 OutOfMemory 异常
OutOfMemory Exception while executing JAVA Mapping
我必须传输大文件(500 MB+...也可以是 1GB)。这些文件必须是 base64 编码的,编码后的字符串必须放在 XML 文件中。虽然我的以下代码适用于较小的文件(30 - 50 MB),但它不适用于大于 100 MB 的文件。
我正在使用 SUN 的 base64 编码器 (sun.misc.BASE64Encoder).
public void execute(InputStream inputstream, OutputStream outputstream) throws StreamTransformationException{
try
{
String sourceFileName = "test_file";
String ReceiverStr = "";
//2. Convert input data in Base64Encoded string
BASE64Encoder encoder = new BASE64Encoder();
byte input[] = new byte[inputstream.available()];
inputstream.read(input);
String base64Encoded = encoder.encode(input);
//3. Build the SOAP request format
String serverUrl = "http://website/url";
String soapEnvelope = "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:soap=\"http://schemas.microsoft.com/sharepoint/soap/\">";
String soapHeader = "<soapenv:Header/><soapenv:Body><soap:CopyIntoItems><soap:SourceUrl>C:\Users\Desktop\test_file.txt</soap:SourceUrl><soap:DestinationUrls><soap:string>" + serverUrl + "</soap:string></soap:DestinationUrls><soap:Fields><soap:FieldInformation " + "Type=" + "\"Text\"" + " DisplayName=\"" + sourceFileName + "\"" + " InternalName=\"" + sourceFileName + "\"" + " Id=\"deff4b5c-b727-414c-893d-c56a8e12455f\"" + " Value=\"" + sourceFileName + "\"/></soap:Fields>";
String soapStream = "<soap:Stream>" + base64Encoded + "</soap:Stream>";
ReceiverStr = soapEnvelope + soapHeader + soapStream + "</soap:CopyIntoItems></soapenv:Body></soapenv:Envelope>";
//4. Write the SOAP request to receiver channel
outputstream.write(ReceiverStr.getBytes());
}
catch(Exception e) {
throw new StreamTransformationException(e.toString());
}
}
当我尝试在 运行 时查看消息时,不会显示整条消息,而是在 base64Encoded 字符串中插入 运行 中间。
以下是在我的系统中执行 JAVA 代码时出现的错误。
请注意,我的服务器设置可以轻松传输 1GB+ 文件,而不会出现任何 JAVA 堆大小错误或文件 t运行cation。
你能告诉我如何使用上述逻辑处理大文件吗?
谢谢,
阿比舍克。
启动应用程序时,您配置了什么样的堆大小?
据我所知,默认堆大小为 256kb,并且由于您一次将整个文件编码为 base64,因此您需要将堆大小设置为至少 1.5 倍的文件大小。
查看如何使用设置和使用 VM 参数“-Xmx”。
您的代码有很多问题。
首先,我建议切换到 OutputStreamWriter
而不是 OutputStream
作为你的参数(你不是在写二进制数据,而是字符数据)。
首先写出 headers,然后开始以 8192 字节的块为单位处理输入流(永远不要使用 inputstream.available()
,你不需要它)。如果您不知道 "standard" 处理流的方式,请阅读 Java IO Essentials。基本上你读取了一大块数据,将其转换为 Base64
写出并重复(直到输入流耗尽)。笔记!您必须确保对大小可被 3 整除的块进行编码(最后一个块除外),否则将应用填充并且会弄乱结果。最后一个块可以有填充。
之后就可以写页脚了,整个过程几乎不占用内存。
看看你的代码,你存储了三次数据:
第一次是来自输入流的字节数组。第二次是在编码的字符串中,最后将其写入输出流。
你可以做些什么来优化这一点是将读取从输入 stream/encoding 和编码字符串写入输出流分开。这样你就可以在编码后释放输入字节数组,并且可以释放内存。更好的解决方案是当编码器直接写入输出流或直接写入 encoding output stream.
但是您仍然需要考虑可以处理的最大文件大小,并相应地调整堆设置:How to deal with "java.lang.OutOfMemoryError: Java heap space" error (64MB heap size)
我必须传输大文件(500 MB+...也可以是 1GB)。这些文件必须是 base64 编码的,编码后的字符串必须放在 XML 文件中。虽然我的以下代码适用于较小的文件(30 - 50 MB),但它不适用于大于 100 MB 的文件。 我正在使用 SUN 的 base64 编码器 (sun.misc.BASE64Encoder).
public void execute(InputStream inputstream, OutputStream outputstream) throws StreamTransformationException{
try
{
String sourceFileName = "test_file";
String ReceiverStr = "";
//2. Convert input data in Base64Encoded string
BASE64Encoder encoder = new BASE64Encoder();
byte input[] = new byte[inputstream.available()];
inputstream.read(input);
String base64Encoded = encoder.encode(input);
//3. Build the SOAP request format
String serverUrl = "http://website/url";
String soapEnvelope = "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:soap=\"http://schemas.microsoft.com/sharepoint/soap/\">";
String soapHeader = "<soapenv:Header/><soapenv:Body><soap:CopyIntoItems><soap:SourceUrl>C:\Users\Desktop\test_file.txt</soap:SourceUrl><soap:DestinationUrls><soap:string>" + serverUrl + "</soap:string></soap:DestinationUrls><soap:Fields><soap:FieldInformation " + "Type=" + "\"Text\"" + " DisplayName=\"" + sourceFileName + "\"" + " InternalName=\"" + sourceFileName + "\"" + " Id=\"deff4b5c-b727-414c-893d-c56a8e12455f\"" + " Value=\"" + sourceFileName + "\"/></soap:Fields>";
String soapStream = "<soap:Stream>" + base64Encoded + "</soap:Stream>";
ReceiverStr = soapEnvelope + soapHeader + soapStream + "</soap:CopyIntoItems></soapenv:Body></soapenv:Envelope>";
//4. Write the SOAP request to receiver channel
outputstream.write(ReceiverStr.getBytes());
}
catch(Exception e) {
throw new StreamTransformationException(e.toString());
}
}
当我尝试在 运行 时查看消息时,不会显示整条消息,而是在 base64Encoded 字符串中插入 运行 中间。
以下是在我的系统中执行 JAVA 代码时出现的错误。
谢谢,
阿比舍克。
启动应用程序时,您配置了什么样的堆大小? 据我所知,默认堆大小为 256kb,并且由于您一次将整个文件编码为 base64,因此您需要将堆大小设置为至少 1.5 倍的文件大小。
查看如何使用设置和使用 VM 参数“-Xmx”。
您的代码有很多问题。
首先,我建议切换到 OutputStreamWriter
而不是 OutputStream
作为你的参数(你不是在写二进制数据,而是字符数据)。
首先写出 headers,然后开始以 8192 字节的块为单位处理输入流(永远不要使用 inputstream.available()
,你不需要它)。如果您不知道 "standard" 处理流的方式,请阅读 Java IO Essentials。基本上你读取了一大块数据,将其转换为 Base64
写出并重复(直到输入流耗尽)。笔记!您必须确保对大小可被 3 整除的块进行编码(最后一个块除外),否则将应用填充并且会弄乱结果。最后一个块可以有填充。
之后就可以写页脚了,整个过程几乎不占用内存。
看看你的代码,你存储了三次数据:
第一次是来自输入流的字节数组。第二次是在编码的字符串中,最后将其写入输出流。
你可以做些什么来优化这一点是将读取从输入 stream/encoding 和编码字符串写入输出流分开。这样你就可以在编码后释放输入字节数组,并且可以释放内存。更好的解决方案是当编码器直接写入输出流或直接写入 encoding output stream.
但是您仍然需要考虑可以处理的最大文件大小,并相应地调整堆设置:How to deal with "java.lang.OutOfMemoryError: Java heap space" error (64MB heap size)