# HG changeset patch # User Chong Yidong # Date 1274462967 14400 # Node ID 9480d787845f9244589d2ef59b660b1a17d8f98e # Parent e6ab17110c0dfa5001a023c46fd1e188e59239bd Improve image cache clearing logic (Bug#6230). * xdisp.c (redisplay_internal): Clear caches even if redisplaying just one window. * image.c (Vimage_cache_eviction_delay): Decrease to 300. (clear_image_cache): If the number of cached images is unusually large, decrease the cache eviction delay. diff -r e6ab17110c0d -r 9480d787845f src/ChangeLog --- a/src/ChangeLog Fri May 21 09:31:45 2010 -0700 +++ b/src/ChangeLog Fri May 21 13:29:27 2010 -0400 @@ -1,3 +1,12 @@ +2010-05-21 Chong Yidong + + * xdisp.c (redisplay_internal): Clear caches even if redisplaying + just one window. + + * image.c (Vimage_cache_eviction_delay): Decrease to 300. + (clear_image_cache): If the number of cached images is unusually + large, decrease the cache eviction delay (Bug#6230). + 2010-05-21 Glenn Morris * Makefile.in (${ns_appdir}, ${ns_appbindir}Emacs, ns-app): diff -r e6ab17110c0d -r 9480d787845f src/image.c --- a/src/image.c Fri May 21 09:31:45 2010 -0700 +++ b/src/image.c Fri May 21 13:29:27 2010 -0400 @@ -1582,29 +1582,56 @@ { struct image_cache *c = FRAME_IMAGE_CACHE (f); - if (c && (!NILP (filter) || INTEGERP (Vimage_cache_eviction_delay))) - { - EMACS_TIME t; - unsigned long old; - int i, nfreed; - - EMACS_GET_TIME (t); - old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay); + if (c) + { + int i, nfreed = 0; /* Block input so that we won't be interrupted by a SIGIO while being in an inconsistent state. */ BLOCK_INPUT; - for (i = nfreed = 0; i < c->used; ++i) + if (!NILP (filter)) + { + /* Filter image cache. */ + for (i = 0; i < c->used; ++i) + { + struct image *img = c->images[i]; + if (img && (EQ (Qt, filter) + || !NILP (Fmember (filter, img->dependencies)))) + { + free_image (f, img); + ++nfreed; + } + } + } + else if (INTEGERP (Vimage_cache_eviction_delay)) { - struct image *img = c->images[i]; - if (img != NULL - && (NILP (filter) ? img->timestamp < old - : (EQ (Qt, filter) - || !NILP (Fmember (filter, img->dependencies))))) + /* Free cache based on timestamp. */ + EMACS_TIME t; + unsigned long old; + int delay, nimages = 0; + + for (i = 0; i < c->used; ++i) + if (c->images[i]) + nimages++; + + /* If the number of cached images has grown unusually large, + decrease the cache eviction delay (Bug#6230). */ + delay = XFASTINT (Vimage_cache_eviction_delay); + if (nimages > 40) + delay = max (1, 1600 * delay / (nimages*nimages)); + + EMACS_GET_TIME (t); + old = EMACS_SECS (t) - delay; + + for (i = 0; i < c->used; ++i) { - free_image (f, img); - ++nfreed; + struct image *img = c->images[i]; + if (img && img->timestamp < old) + { + free_image (f, img); + ++nfreed; + } } } @@ -8520,11 +8547,14 @@ Vx_bitmap_file_path = decode_env_path ((char *) 0, PATH_BITMAPS); DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay, - doc: /* Time after which cached images are removed from the cache. -When an image has not been displayed this many seconds, remove it -from the image cache. Value must be an integer or nil with nil -meaning don't clear the cache. */); - Vimage_cache_eviction_delay = make_number (30 * 60); + doc: /* Maximum time after which images are removed from the cache. +When an image has not been displayed this many seconds, Emacs +automatically removes it from the image cache. If the cache contains +a large number of images, the actual eviction time may be shorter. +The value can also be nil, meaning the cache is never cleared. + +The function `clear-image-cache' disregards this variable. */); + Vimage_cache_eviction_delay = make_number (300); } void diff -r e6ab17110c0d -r 9480d787845f src/xdisp.c --- a/src/xdisp.c Fri May 21 09:31:45 2010 -0700 +++ b/src/xdisp.c Fri May 21 13:29:27 2010 -0400 @@ -12499,22 +12499,25 @@ if (windows_or_buffers_changed && !pause) goto retry; - /* Clear the face cache eventually. */ - if (consider_all_windows_p) - { - if (clear_face_cache_count > CLEAR_FACE_CACHE_COUNT) - { - clear_face_cache (0); - clear_face_cache_count = 0; - } -#ifdef HAVE_WINDOW_SYSTEM - if (clear_image_cache_count > CLEAR_IMAGE_CACHE_COUNT) - { - clear_image_caches (Qnil); - clear_image_cache_count = 0; - } + /* Clear the face and image caches. + + We used to do this only if consider_all_windows_p. But the cache + needs to be cleared if a timer creates images in the current + buffer (e.g. the test case in Bug#6230). */ + + if (clear_face_cache_count > CLEAR_FACE_CACHE_COUNT) + { + clear_face_cache (0); + clear_face_cache_count = 0; + } + +#ifdef HAVE_WINDOW_SYSTEM + if (clear_image_cache_count > CLEAR_IMAGE_CACHE_COUNT) + { + clear_image_caches (Qnil); + clear_image_cache_count = 0; + } #endif /* HAVE_WINDOW_SYSTEM */ - } end_of_redisplay: unbind_to (count, Qnil);