-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Leak on Linux? #955
Comments
Hello, how is memory usage being measured? If RSS, please remember this includes free memory that has not (yet) been returned to the OS, which explains why different OSs report different RSS for the same task. If you've not seen then, there have been quite a few related questions previously: |
Yes, RSS being the main indicator. But I also rely on buff/cache and avail memory to better understand "free-able" memory, and this indicates that this memory is never being released back. This memory doesn't seem to reside in the V8 memory space, as indicated from dozens of heap dump tests. Thanks for links to the other issues that seem connected. I'm not entirely sure the issue is fully understood though. I'm not convinced it's an issue with sharp either, but I'm hoping we can work around the problem as the impact is quite significant. We're using ~5x the memory we should be, which becomes a big deal when you're serving (many) millions of requests/day. I'll continue investigating the related cases. So far I've found no workaround to the problem that doesn't involve not using |
It's worth subscribing to nodejs/node#1671 for V8 updates that will improve GC of Buffer objects. If you're not already doing so, you might want to experiment with a different memory allocator such as jemalloc. You'll probably see less fragmentation, but that's still dealing with the effect rather than the cause. |
Will do, thanks. Probably no surprise, but I was at least able to correlate usage with the In my isolated (sharp-only) test these were the findings:
|
Does the prod environment use 8 real CPU cores or is this "vCPU" hyper-threading? If the latter, perhaps also experiment halving concurrency to improve throughput (and reduce the memory effects). |
I am artificially limiting cores to keep memory in check, but at the cost of up to 30% slower response times. Temporary test. |
Feel free to close this as a duplicate of others. But from everything I've learned of the problem thus far there doesn't seem to be any conclusive evidence that this is a Node and/or V8 issue. From the symptoms of the isolated tests I've run (as well as others) it does seem to be any issue with sharp or vips as this isn't a common problem in the node community to see run-away memory increases of this nature. I was able to verify this is not a case of GC'd memory not being released back to the OS, confirming that this memory was in-use and any reduction in available memory resulting in memory allocation failure. But as I said, nothing conclusive either way. I tried to investigate ways to resolve/workaround the problem within Sharp but was unsuccessful -- hopefully someone with more expertise with V8 native modules will have better luck. |
Could memory fragmentation explain this? |
I haven't proven/disproven that theory. But with the modest number of objects being processed to achieve such high memory usage, it'd seem to require some pretty severe fragmentation to justify this. Is your thoughts that it's fragmentation in V8 or native space? |
Are you using Node 8? If not, do you see the same RSS levels with it? Were you able to try jemalloc? It provides useful debugging via malloc_stats_print. Given you're using CentOS, have you tried disabling transparent huge pages? |
Not using 8 in prod, but yes was able to reproduce similar RSS levels (with 8.5.0) in the isolated test. Might be a bit before I can look into the other options but will keep in mind, thanks. |
If sharpen or blur operations are being used then the small leak fixed in https://github.com/jcupitt/libvips/issues/771 may be related here. |
The test sample for this topic doesn't use those two operations so probably unrelated. But we do use them on occasion, thanks! |
I've found that running my sharp modules in a child_process spawn that exits once it's completed works really well for me. It keeps the memory load down. |
Was hoping to avoid spawning a child process, but it is something I had considered as well. It's manageable at the moment so holding out for now. |
@asilvas The sharp tests just revealed a memory leak on one possible libvips error path when using |
Excellent find (and fix), @lovell ! Thanks, these sort of fixes make a big difference when processing millions of images. Any idea when this fix will be available? |
@asilvas The next libvips v8.6.1 patch release should contain this fix, which then allows the release of sharp v0.19.0. |
libvips v8.6.1 is out |
@asilvas Are you seeing an improvement with the latest libvips/sharp? |
In testing, will let you know next week. |
I am currently having the same issue. Stack information: Libraries versions: Sharp: I also use a lot of JPEG toBuffer. Even under stress the V8 heap doesn't change, but the non-heap memory grows consistently on every request. Before the update my memory usage was steadily at 300MB using libvips 7.42.3 and sharp 0.17.1 |
Seeing similar results after ~24 hours in production: Overall memory usage patterns seems to be a bit improved, but still far higher than I'd expect (eventually reaching 2GB, perhaps related to prior suggestions). I have noticed some perf improvements overall, though it could be due to the relatively short life of the new containers. I might revisit doing some more memory profiling at some point, but it'll have to wait for now. I'll let you know if any new data surfaces. |
@asilvas would you mind sharing the throughput of your servers and if they are many different images? |
@vinerz We generate over 20 million images per day, from millions of source images. Overall throughput is much higher, but that part is unrelated to this topic. Powered by https://github.com/asilvas/node-image-steam, and of course sharp+libvips. |
Thanks for the answer! Based on this information, I can see that my leakage is getting larger much, much faster than yours, even tough manipulating only 200 thousand images per day from around 50 thousand different sources. It might be related to the fact that I use I'll try disabling libvips cache to see what happens. |
We use Our sharp options include:
I've toyed with options quite a bit in the past, but might be worth revisiting with the recent changes/fixes. |
I modified the core app flow to use a single sharp object and changed all Currently using |
Solved my problem with your help.
Up to 70x child processes and still have plenty of memory left. Thanks for all your work! |
Please see #2607 for a change in the default concurrency for glibc-based Linux users that will be in v0.28.0. |
not related...but @vinerz what application were you using to monitor memory in this comment? Is that heroku's dashboard? |
Hey @FoxxMD, that's New Relic's application monitor for node 😄 |
refs lovell/sharp#955 (comment) - we've seen Ghost hogging memory whenever images are uploaded - it seems to be due to an issue with memory fragmentation, because a heap snapshot of a container after the memory grows shows nothing in JS code - we've been using jemalloc in production but it still seems to occur - this change has been suggested on the referenced thread in order to improve fragmentation on top of using jemalloc - can easily revert if it causes issues
const sharp = require("sharp");
(async () => {
await Promise.all([...Array(100)].map(() => sharp("./test.webp").rotate(90).toBuffer()));
})(); |
Been troubleshooting a leak in https://github.com/asilvas/node-image-steam (processes millions of images every day) and originally thought it was in my project but after a number of heap dump checks I determined it wasn't a leak in V8.
In order to break it down the simplest parts I recorded the traffic in a serial form so it can be replayed in a pure sharp script.
https://gist.github.com/asilvas/474112440535051f2608223c8dc2fcdf
It's downloading these files on the fly, which avoids any FS caching which will bloat memory usage, and forwards the instructions (in sharp.log) directly to sharp, one at a time.
Memory usage gets into 500MB+ within a few mins (at least on Docker+CentOS), and seems to eventually peak. On some systems I've seen over 2GB usage. Only processing a single image at a time should be pretty flat in memory usage. Have you seen this before? Any ideas? I wasn't aware of anything sharp/vips was doing that should be triggering Linux's file caching.
Edit: While memory usage on Mac is still higher than I expect for a single image processed at a time (~160MB) after a couple hundred images, it's nowhere near as high as on Linux.. And it seems to peak quickly. So it appears to be a linux only issue. Docker is also involved, so not ruling that out either.
The text was updated successfully, but these errors were encountered: