简体   繁体   English

执行JAVA映射时出现OutOfMemory异常

[英]OutOfMemory Exception while executing JAVA Mapping

I have to transfer big files (500 MB+...can also be of 1GB in size). 我必须传输大文件(500 MB + ...也可以是1GB大小)。 These files have to be base64 encoded and the encoded string has to be put in a XML file. 这些文件必须使用base64编码,并且编码后的字符串必须放在XML文件中。 While my below code works good for smaller files (30 - 50 MB) it fails for files great than 100 MB. 虽然我的以下代码适用于较小的文件(30-50 MB),但不适用于大于100 MB的文件。 I am using base64 encoder from SUN (sun.misc.BASE64Encoder). 我正在使用SUN(sun.misc.BASE64Encoder)中的base64编码器。

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());  
        }
    }

When I try to see the message at run-time, then the entire message is not displayed and it is truncated in-between in the base64Encoded string. 当我尝试在运行时查看该消息时,则不会显示整个消息,并且会在base64Encoded字符串中将其截断。 Below is the error that is seen in my system on executing the JAVA code. 以下是在我的系统中执行JAVA代码时看到的错误。 在此处输入图片说明 Please note that my server settings can otherwise easily transfer 1GB+ files without any JAVA Heap size error or file truncation. 请注意,否则我的服务器设置可以轻松传输1GB以上的文件,而不会出现任何JAVA Heap大小错误或文件截断的情况。 Can you please let me know how can I process big files using above logic? 您能告诉我如何使用上述逻辑处理大文件吗?

Thanks, 谢谢,

Abhishek. 阿布舍克

There are plenty of things wrong with your code. 您的代码有很多错误。 First of all I recommend switching to OutputStreamWriter instead of OutputStream as your parameter (you're not writing binary data, but character data). 首先,我建议切换到OutputStreamWriter而不是OutputStream作为参数(您不是在写二进制数据,而是在写字符数据)。

Write out the headers first, then start processing the inputstream in chunks of let's say 8192 bytes (don't use inputstream.available() ever, you won't need it). 首先写出标头,然后开始处理8192字节的块的输入inputstream.available()永远不要使用inputstream.available() ,就不需要它了)。 If you don't know the "standard" way of processing streams, go through Java IO Essentials . 如果您不知道处理流的“标准”方式,请阅读Java IO Essentials Basically you read a chunk of data, convert it to Base64 write it out and repeat (until inputstream is exhausted). 基本上,您读取了一块数据,将其转换为Base64 ,然后将其写入并重复(直到输入流用尽)。 NOTE! 注意! You have to make sure you encode chunks of size divisible by 3 (except for the last chunk), otherwise there will be padding applied and it will mess up the result. 您必须确保对大小可被3整除的块进行编码(最后一个块除外),否则将应用填充并弄乱结果。 The last chunk can have the padding. 最后一块可以有填充。

After that you can write the footers, and the whole process will take barely any memory. 之后,您可以编写页脚,整个过程几乎不会占用任何内存。

Taking a look at your code you store the data three times: 看一下代码,您将数据存储了三次:

The first time is in byte array from the input stream. 第一次是来自输入流的字节数组。 The second time is in the encoded String and finally you write it to the output stream. 第二次是在编码的String中,最后将其写入输出流。

What you can do to optimize this a bit is to split the reading from the input stream/encoding and the writing of the encoded string to the output stream. 您可以做些优化的工作是将读取数据从输入流/编码中分离出来,并将编码后的字符串写入输出流中。 That way you can let go of the input byte array once encoded and the memory can be freed. 这样,一旦编码,您就可以释放输入字节数组,并且可以释放内存。 An even better solution would be when the encoder directly writes to the Output stream or directly write to an encoding output stream . 更好的解决方案是当编码器直接写入Output流或直接写入编码输出流时

However you will still have to consider what the maximum file size should be that can be processed and adjust the heap setting accordingly: How to deal with "java.lang.OutOfMemoryError: Java heap space" error (64MB heap size) 但是,您仍然必须考虑可以处理的最大文件大小,并相应地调整堆设置: 如何处理“ java.lang.OutOfMemoryError:Java堆空间”错误(64MB堆大小)

What kind of heap size did you configure, when you started the application? 启动应用程序时,您配置了哪种堆大小? As far as I remember, the default heap size is 256kb and since you encode your complete file at once as base64, you need to set a heap size of at least 1.5 times your filesize. 据我所知,默认堆大小为256kb,由于您一次将完整文件编码为base64,因此需要将堆大小设置为文件大小的至少1.5倍。

Check out how to use set and use the VM-argument "-Xmx". 了解如何使用set和使用VM参数“ -Xmx”。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM