-
-
Notifications
You must be signed in to change notification settings - Fork 649
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
Fix for hidden leaks in ThreadPool #1240
Fix for hidden leaks in ThreadPool #1240
Conversation
… image object. As that image could not be freed from cache, for each sink operation done for that image the code was creating new pools and threads without freeing the previous one. SO the more number of threads and the more operations the bigger the hidden leak was. The fix just creates the objects not locally to that image, and also free them in its destroy functions
Looking at threadpool again, I think we should refactor a bit. For example Let's merge this, then I'll have a go at fixing up threadpool. |
I removed that connection in the PR (https://github.com/libvips/libvips/pull/1240/files#diff-6d3018acf7545e1112df2c11914d2f92L805). Also a question, wouldn't make sense to have a thread pool that is reused for the whole vips live? I know it is not an easy thing to do, but spawning new threads have a cost and in my application it seems libvips is creating/destroying hundreds of thousands of them... |
Quick update -- this test program: /* compile with
*
* gcc -g -Wall soak7.c `pkg-config vips --cflags --libs`
*/
#include <vips/vips.h>
#include <vips/vector.h>
int
main(int argc, char* argv[])
{
int i;
VipsImage* image;
if (VIPS_INIT(argv[0]))
vips_error_exit(NULL);
vips_cache_set_max(0);
image = vips_image_new_from_file(argv[1], NULL);
for (i = 0; i < 100000; ++i) {
VipsImage* tmp;
double avg;
printf("loop %d ..\n", i);
vips_extract_area(image, &tmp, 0, 0, 1000, 1000, NULL);
vips_avg(image, &avg, NULL);
g_object_unref(tmp);
}
g_object_unref(image);
vips_shutdown();
return 0;
} After this patch, runs like this:
So it takes a while to stabilise (thanks to memory fragmentation) but it does seem to, eventually. |
clean up and simplify after #1240
Yes, it makes a new threadpool for every evaluation loop. I did consider a system to recycle them, but it was a lot of work to guarantee that a threadpool was no longer indirectly linked to an image. For example, threads use thread-private storage to keep certain caches, and they would all need to be flushed before reassigning a thread to a new image. Creating and destroying threads is pretty quick, and evaluation loops generally take a long time, so the create/destroy cost is only a small percentage, unless you are processing tiny (just a few pixels) images. |
I understand, makes sense :). Thanks for the explanation. |
ThreadPool was allocating memory for threads and pools locally to the image object. As that image could not be freed from cache, for each sink operation done for that image the code was creating new pools and threads without freeing the previous ones. So, the more number of threads and the more operations the bigger the hidden leak was. The fix just creates the objects not locally to that image, and also free them in its destroy functions