Verson:
JDK21
spring-boot-starter-web 3.5.0
When I upload file to springmvc applicaion, and use MultipartFile#getBytes. it will OOM,If the total size of the attachments I have uploaded exceeds the direct memory size.OOM occurs.
this is the recurrent demo project link https://github.com/sxl-vay/test-direct-memory.git
And I found out that the problem was caused by this commit 4e896c8125c957ffa63238d10444f76d9913b549
Comment From: bclozel
See https://github.com/spring-projects/spring-framework/pull/30155#issuecomment-2945110239
I guess the same could happen with the heap if the parts are too large. I don't understand what's expected of us here.
Have you considered using other methods available in MultipartFile
to transfer/copy data more efficiently without loading the entire content in memory? I would argue that heap or native memory won't make a difference here: if you allow clients to send very large multipart requests and you're loading the entire contents in memory, this is a potential DoS attack on your application, not a bug in Spring. Please advise.
Comment From: sxl-vay
See #30155 (comment)
I guess the same could happen with the heap if the parts are too large. I don't understand what's expected of us here. Have you considered using other methods available in
MultipartFile
to transfer/copy data more efficiently without loading the entire content in memory? I would argue that heap or native memory won't make a difference here: if you allow clients to send very large multipart requests and you're loading the entire contents in memory, this is a potential DoS attack on your application, not a bug in Spring. Please advise.
You can take a look at my testing project. I didn't upload a huge file at once, but uploaded files multiple times and called this method multiple times. However, the direct memory occupied by uploading files is not reclaimed, which leads to OOM.
And I when I change jdk to 24.This problem no longer exists.This may also be an issue with JDK
Comment From: sxl-vay
I think I have find the reason
In jdk, this commit fix it :
8344882: (bf) Temporary direct buffers should not count against the upper limit on direct buffer memory
commit number: 0312694c46b4fb3455cde2e4d1f8746ad4df8548
Comment From: bclozel
I have used your sample application and tried to reproduce the issue. On both Java 24 and 17.0.15 I am not seeing the memory increase dramatically nor OOM; I'm probably missing something in my setup?
Looking closely at your sample, this really boils down to calling org.springframework.web.multipart.MultipartFile#getBytes
for a large file, which in turns calls java.io.InputStream#readAllBytes
. Now, whether Java changed how the memory is temporary allocated there or not, this is mostly out of Spring's control. Calling this in the first place for possibly large file is an application issue by itself. I guess this was mostly the case in the sample to reproduce the behavior.
I'm closing this issue as Spring is not responsible there and calling this JDK method is the sensible thing to do and aligns with java.io.InputStream
's Javadoc.