One of the download we are using byte[] as return type
@PostMapping("/downloadReport")
public ResponseEntity<byte[]> downlodReport(@RequestBody Request request) {
byte[] fileContents = someByteContent;
ResponseEntity.ok().header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileName + "\"")
.contentType(MediaType.parseMediaType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"))
.body(fileContents)
}
We are seeing more than 100% CPU while downloading the files, when I googled in most of the examples I found with Resource as a return type, does the file loads into memory when we return as byte[] which is consuming memory while downloading the file? does it get's better in terms of memory usage if I use Resource as a return type and use InputStreamResource resource = new InputStreamResource(new FileInputStream(file));
any suggestions are appreciated
When you create a byte[] you are telling Java to "create me a list of bytes in memory, and return the pointer to those bytes." Specifically, the object reference gets allocated on the heap and the pointer is stored in the stack.
So, thusly, when you use a byte[] to store a file, the whole contents of the file is required to be loaded into memory.
When you return byte[], it also loads the whole contents from memory. I would say that in most use cases, this is not a problem, but it largely depends on the purpose and size of those files.
If the file is something that is going to be regularly large, I would try something like this:
InputStreamResource inputStreamResource = new InputStreamResource(inputStream); httpHeaders.setContentLength(contentLengthOfStream); return new ResponseEntity(inputStreamResource, httpHeaders, HttpStatus.OK);java - return-a-stream-with-spring-mvcs-responseentity.
But I think some testing needs to be done to rule at what point returning a byte[] is preferable and at what point returning the stream is preferable. I'll do some testing and get back to you.
Now, another option you might want to explore is not storing files in a database, generating them and storing them on the filesystem, and then just returning a forward:/ request in the view to redirect the user to the file, this way, you offload the responsibility of serving the file to the web server, which is often better suited for handling static resources efficiently anyway.
Quick Edit:
Wanted to add some source code for you to play with:
And the unit tests:
From my testing, I found that the second derivative is monotonically increasing on the interval [0, 32), zero at [32, 64], and increasing again from (64, inf) on both download stream and download bytes.
However, I did notice a big difference in the max lengths achieved by both. In a binary search of 30 iterations, Streaming reaches a length of 8388608 bytes at 188 msec on my local; whereas bytes can only reach 1048576 bytes at around 174 msec with the same number of iterations.
Stream and byte seem to both be reasonably quick at retrieving results, but I did notice several out of memory errors as we reach higher values.
I hope this helps.