如何修复 java.lang.OutOfMemoryError: Java heap space error?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/55331820/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to fix java.lang.OutOfMemoryError: Java heap space error?
提问by naveenkumar
I have a file with size of 32 MB, I have downloaded it from DocuShare server to DocuShare temp folder. I am trying to read the file content from it to create a file. I get error when I URL encode my base64 content. I am not getting any exception when I run the same code a simple java application. But when I use the same code in DocuShare service to get document content I get Exception. HTTP Status 500 - org.glassfish.jersey.server.ContainerException: java.lang.OutOfMemoryError: Java heap space
我有一个大小为 32 MB 的文件,我已将它从 DocuShare 服务器下载到 DocuShare 临时文件夹。我正在尝试从中读取文件内容以创建文件。当我对 base64 内容进行 URL 编码时出现错误。当我在一个简单的 Java 应用程序中运行相同的代码时,我没有收到任何异常。但是当我在 DocuShare 服务中使用相同的代码来获取文档内容时,我得到了异常。HTTP 状态 500 - org.glassfish.jersey.server.ContainerException:java.lang.OutOfMemoryError:Java 堆空间
org.glassfish.jersey.server.ContainerException: java.lang.OutOfMemoryError: Java heap space
org.glassfish.jersey.server.ContainerException:java.lang.OutOfMemoryError:Java 堆空间
File file = new File(filePath);
FileInputStream fileInputStreamReader = new FileInputStream(file);
byte[] bytes = new byte[(int)file.length()];
fileInputStreamReader.read(bytes);
String encodedBase64 = String encodedBase64 = java.util.Base64.getEncoder().encodeToString(bytes);
String urlEncoded = URLEncoder.encode(encodedBase64);
How to fix this error? Do I need to increase my tomcat heap size?
如何修复此错误?我需要增加我的 tomcat 堆大小吗?
采纳答案by Pavel Smirnov
Base64 converts each 3 bytes into 4 letters. That means you can read your data in chunks and decode it in the same way as you would decode the whole file.
Base64 将每 3 个字节转换为 4 个字母。这意味着您可以分块读取数据并以与解码整个文件相同的方式对其进行解码。
Try this:
尝试这个:
File file = new File(filePath);
FileInputStream fileInputStreamReader = new FileInputStream(file);
StringBuilder sb = new StringBuilder();
Base64.Encoder encoder = java.util.Base64.getEncoder();
int bufferSize = 3 * 1024; //3 mb is the size of a chunk
byte[] bytes = new byte[bufferSize];
int readSize = 0;
while ((readSize = fileInputStreamReader.read(bytes)) == bufferSize) {
sb.append(encoder.encodeToString(bytes));
}
if (readSize > 0) {
bytes = Arrays.copyOf(bytes, readSize);
sb.append(encoder.encodeToString(bytes) );
}
String encodedBase64 = sb.toString();
回答by Vinay Avasthi
If you have large files, you will always run into OOM errors depending on size of file. If your goal is to base64 encoding using Apache Commons Base64 Streams.
如果您有大文件,您将始终遇到 OOM 错误,具体取决于文件大小。如果您的目标是使用 Apache Commons Base64 Streams 进行 base64 编码。
回答by Svetlin Zarev
There are two ways in which you can fix the issue.
有两种方法可以解决问题。
You can increase the heap size, but IMO this is a bad solution, because you will hit the same issue if you get several parallel requests or when you try to process a bigger file.
You can optimize your algorithm - instead of storing several copies of your file in-memory, you can process it in a streaming fashion, thus not holding more than several KBs in memory:
import java.io.InputStream; import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Base64; public class Launcher { public static void main(String[] args) throws Exception { final Path input = Paths.get("example"); final Path output = Paths.get("output"); try (InputStream in = Files.newInputStream(input); OutputStream out = Base64.getUrlEncoder().wrap(Files.newOutputStream(output))) { final byte[] buffer = new byte[1024 * 8]; for (int read = in.read(buffer); read > 0; read = in.read(buffer)) { out.write(buffer, 0, read); } } } }
您可以增加堆大小,但 IMO 这是一个糟糕的解决方案,因为如果您收到多个并行请求或尝试处理更大的文件,您将遇到相同的问题。
您可以优化您的算法——而不是在内存中存储多个文件副本,您可以以流式方式处理它,从而在内存中不超过几个 KB:
import java.io.InputStream; import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Base64; public class Launcher { public static void main(String[] args) throws Exception { final Path input = Paths.get("example"); final Path output = Paths.get("output"); try (InputStream in = Files.newInputStream(input); OutputStream out = Base64.getUrlEncoder().wrap(Files.newOutputStream(output))) { final byte[] buffer = new byte[1024 * 8]; for (int read = in.read(buffer); read > 0; read = in.read(buffer)) { out.write(buffer, 0, read); } } } }
PS: If you really need the URL encoder, you'll have to create a streaming version of it, but I think a URL-safe base64 would be more than enough
PS:如果您真的需要 URL 编码器,则必须创建它的流媒体版本,但我认为 URL 安全的 base64 就足够了