【发布时间】:2020-04-25 02:54:07
【问题描述】:
我需要从网络请求中返回一个相当大的文件。该文件大小约为 670mb。在大多数情况下,这可以正常工作,但一段时间后会抛出以下错误:
java.lang.OutOfMemoryError: Direct buffer memory
at java.nio.Bits.reserveMemory(Bits.java:694) ~[na:1.8.0_162]
at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:123) ~[na:1.8.0_162]
at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:311) ~[na:1.8.0_162]
at sun.nio.ch.Util.getTemporaryDirectBuffer(Util.java:241) ~[na:1.8.0_162]
at sun.nio.ch.IOUtil.read(IOUtil.java:195) ~[na:1.8.0_162]
at sun.nio.ch.FileChannelImpl.read(FileChannelImpl.java:159) ~[na:1.8.0_162]
at sun.nio.ch.ChannelInputStream.read(ChannelInputStream.java:65) ~[na:1.8.0_162]
at sun.nio.ch.ChannelInputStream.read(ChannelInputStream.java:109) ~[na:1.8.0_162]
at sun.nio.ch.ChannelInputStream.read(ChannelInputStream.java:103) ~[na:1.8.0_162]
at java.nio.file.Files.read(Files.java:3105) ~[na:1.8.0_162]
at java.nio.file.Files.readAllBytes(Files.java:3158) ~[na:1.8.0_162]
我已将堆大小设置为 4096mb,我认为应该足够大以处理此类文件。此外,当发生此错误时,我使用 jmap 进行了堆转储来分析当前状态。我找到了两个相当大的byte[],应该是我要返回的文件。但是堆的大小只有 1.6gb 左右,而不是接近配置的 4gb。
根据类似问题中的其他答案 (https://stackoverflow.com/a/39984276/5126654),我尝试在返回此文件之前运行手动 gc。问题仍然存在,但现在只是零星的。一段时间后问题出现了,但是当我厌倦了再次运行相同的请求时,似乎垃圾收集处理了导致问题的任何原因,但这还不够,因为问题显然仍然可能发生。有没有其他方法可以避免这个内存问题?
【问题讨论】:
-
不要使用
readAllBytes()。它需要一个文件大小的缓冲区。 TCP/IP 一次会发送大约 1500 个字节,因此任何比这大得多的缓冲区都只是浪费时间和空间。
标签: java memory out-of-memory heap-memory