Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Returning a base64 image without memory leak ASP.NET MVC 3

I have some images stored in a database as base64 strings and need to return them from an MVC controller. How can I do that without a memory leak?

Previously I was using this:

return File(Convert.FromBase64String(pictureString), "image/jpeg");

However, the w3wp process starts using up a whole heap of memory for a few photos.

Is there a proper way to do this? Currently I've decided just to set each image to data:image/jpg;base64,string_here and it uses a lot less memory.. but it seems to be a lot slower loading the page too.

Any help is appreciated.

like image 808
chemicalNova Avatar asked Sep 20 '11 05:09

chemicalNova


2 Answers

Previously I was using this:

There is no leak in this code. The problem is that it loads the entire image in memory before streaming it to the response. The memory raises you observe to the w3p process are normal and once the Garbage Collector kicks it it will clean it. You shouldn't really be worried about that unless you are serving some very large images.

The problem with your design is that you use base64 meaning that you need to load the entire contents before being able to decode it back to a byte array. Another approach would have been to store the images as raw data in your database and then use streams to read it in chunks and write those chunks immediately to the response. This way only the chunk currently being processed is loaded into memory at a given point of time.

Yet another approach that I may suggest you is to not store images in the database at all but store them on the file system and only store the path to the image in the database. Then in your controller action all you have to do is to return File(pathToTheImage, "image/jpeg").

As an additional optimization, if those images do not change frequently you could add the proper output caching to the controller action serving those images to avoid hitting it everytime.

like image 157
Darin Dimitrov Avatar answered Sep 30 '22 20:09

Darin Dimitrov


+1 To Darin Dimitrov's comment.

If images / base64 encoded data are more than 85K it will be allocated on LOH (lage objects heap). GC for such allocations is more expensive due to need to wait for generation 2 collection.

Another approach if you have to keep using base64 encoded images is to implement your own stream that reads data from the Base64 encoded value in chunks to avoid allocation of second large block of memory. If you can read string in chunck also you will be able to avoid allocation of objects on LOH and potentially just reuse realitely small buffers to read/decode.

like image 29
Alexei Levenkov Avatar answered Sep 30 '22 19:09

Alexei Levenkov