coobird / thumbnailator

Thumbnailator - a thumbnail generation library for Java
MIT License
5.14k stars 784 forks source link

Unnecessarily High Memory Consumption #134

Open RafatRifaie opened 5 years ago

RafatRifaie commented 5 years ago

Expected behavior

I'm expecting not to see a huge jump in memory while using thumbnailator, downloading twenty images makes the memory go from 250mb to 1300mb.

Steps to reproduce the behavior

I'm downloading 2048px images from a certain url BufferedImage image = getImageFromURL(url); Then i upscale them like this image= Thumbnails.of(finalImage).width(4096).keepAspectRatio(true).scalingMode(ScalingMode.BICUBIC).alphaInterpolation(AlphaInterpolation.SPEED).asBufferedImage(); Then i save each image to a file, and flush the bufferedimage right after, now when i don't do the scaling the memory consumption, stays the same. Only when i try to scale them with thumbnailator do i actually start to have memory issues.

coobird commented 5 years ago

@RafatRifaie How are you getting your memory usage figures? Are those values reported by the operating system?

Also, what JVM heap memory parameters are you using? It could be that if your maximum heap size (-Xmx) is set to a high value, and depending on that the garbage collector may not be aggressively GCing, causing the JVM to ask more memory from the OS. This StackOverflow answer might be helpful in finding out your heap memory parameters.

By the way, the 1.3 GB figure is right about spot on in terms of the amount of memory expected to be used by twenty 4096x4096 images (20 4096 4096 * 4 bytes per pixel is about 1.3 GB), so it makes me believe that your JVM is asking for more memory from the OS from the way it has been configured.

stefan-reich commented 5 years ago

The JVM cannot be trusted to use a conservative amount of memory. When there is a lot of activity from the program (in terms of making temporary objects), it will happily allocate more memory. It's not even absurd; programs might benefit from this. How is the VM to know if you want to conserve memory?

The only ways around this effect for now are

  1. Set a maximum heap size - that obviously does the trick, but you might be forcing yourself into OOM errors.

  2. Make the GC return memory to the OS. For this to work, you have to use the G1 collector and call System.gc often enough.

stefan-reich commented 5 years ago

By the way, the 1.3 GB figure is right about spot on in terms of the amount of memory expected to be used by twenty 4096x4096 images (20 4096 4096 * 4 bytes per pixel is about 1.3 GB), so it makes me believe that your JVM is asking for more memory from the OS from the way it has been configured.

I thought he meant he upscaled them individually and then discarded them?

php-coder commented 3 years ago

Make the GC return memory to the OS. For this to work, you have to use the G1 collector and call System.gc often enough.

BTW Shenandoah GC (see https://dzone.com/articles/choosing-the-right-gc) can also give unused memory back to OS (without System.gc() call).