[求助] Spring 相关,使用了 MultipartFile 进行文件上传,但是抛出了 OOM?

2023-08-15 11:42:18 +08:00
 gzk329

异常提示是直接缓冲区不足,堆外的,没有做最大大小限制,我的程序应该没有内存泄漏
直接缓冲区的 memory 情况
------- used total max usage
direct 183M 183M - 100.00%

org.springframework.web.util.NestedServletException: Handler dispatch failed; nested exception is java.lang.OutOfMemoryError: Direct buffer memoryHandler dispatch failed; nested exception is java.lang.OutOfMemoryError: Direct buffer memory

这种异常考虑是怎么产生的?我重启过程序进程,有些不好排查了

我感觉是服务器当时内存不够了导致的?但是内存很大了 服务器内存使用情况
free -h
------- total used free shared buff/cache available
Mem: 251G 118G 54G 1.1G 79G 130G
Swap: 4.0G 0B 4.0G

目前这个情况也不能复现了,应该怎么继续排查?

1899 次点击
所在节点    Java
12 条回复
shuson
2023-08-15 12:18:18 +08:00
jvm vm arguments 加上个 -XX:MaxDirectMemorySize=512m
gzk329
2023-08-15 13:04:40 +08:00
@shuson 但是我现在是 我没做限制的呀 理论上不应该是无限大到物理内存的上限吗?
shuson
2023-08-15 13:21:08 +08:00
zed1018
2023-08-15 13:28:03 +08:00
感谢楼上,其实如果有 oss ,我更建议是做一次性 token 让 client 直接传到 oss 里
Nooooobycat
2023-08-15 13:46:46 +08:00
直接把上传文件的核心代码发上来吧? 说不定 GPT 能帮你 debug 。
gzk329
2023-08-15 13:54:47 +08:00
@Nooooobycat 第一层上传直接用的 Spring 的 MultipartFile , 不是我写的,在这一层就 Direct buffer memory 不够了
gzk329
2023-08-15 18:00:12 +08:00
这 Spring 的 MultipartFile 是不是有点离谱啊 各种 OOM 用了直接内存区 又不清理
arloor
2023-08-15 18:59:40 +08:00
看下代码
xinshoushanglu
2023-08-15 19:33:34 +08:00
前端上传东西不限制大小的么?传大文件 也直接走 表单上传 那不是对后端压力山大,建议走前端上传 oss 的方式
gzk329
2023-08-16 08:26:49 +08:00
我研究了下好像是因为使用方式的问题,multipartFile.getBytes()这种方式会导致直接内存区使用增加,还不会释放,
multipartFile.transferTo(tempFile)这个方法就不会。

multipartFile.getBytes() 这个方法好像是会拷贝一份 byte[]出来,但是这种不是应该在堆内吗,用完了也就 GC 了,咋会导致直接内存区不断增,一直到溢出啊?

// try (OutputStream out = Files.newOutputStream(tempFile.toPath())) {
// out.write(multipartFile.getBytes());
// } catch (IOException e) {
// e.printStackTrace();
// }
gzk329
2023-08-17 08:42:07 +08:00
定位出一个 jdk 的 bug 了,给 oracle 提了 bug ,多久会有邮件回复啊?
gzk329
2023-09-05 15:39:57 +08:00
这个问题我后来定位出来了,使用 JDK 8
try-with-resource 机制 自动关闭 Files.newOutputStream 生成的流,流正常关闭,堆外内存释放,但是 java.lang.nio.Bits 中的 reserveMemory ,这个内存占用没有被清理,多次操作之后会 OOM 。
改写为 try-with-resource 机制 自动关闭 FileOutputStream 流,就不会有这个问题。
所以推断是 JDK 的 bug

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/965406

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX