Changeset 258908 in webkit
- Timestamp:
- Mar 23, 2020 10:05:50 PM (4 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r258907 r258908 1 2020-03-23 Simon Fraser <simon.fraser@apple.com> 2 3 Safari jetsams with repeated drawImage/getImageData 4 https://bugs.webkit.org/show_bug.cgi?id=207957 5 6 Reviewed by Tim Horton. 7 8 SubimageCacheWithTimer used a DeferrableOneShotTimer to clear itself, but if content 9 adds an entry to the cache on every frame (as might content drawing video frames into a canvas) 10 then the cache was never cleared. Nor was it cleared via a memory warning. 11 12 Fix by tracking cache entries by age, and using a repeating timer to prune old images 13 from the cache. Also hook up the cache to the memory pressure handler, which clears it. 14 15 Reduce the timer frequency from 1s to 500ms, since that was observed to reduce the memory use 16 on the provided testcase from ~600M to ~350M, making jetsam less likely. 17 18 Rename m_images to m_imageCounts to make its role clearer. 19 20 * page/cocoa/MemoryReleaseCocoa.mm: 21 (WebCore::platformReleaseMemory): 22 * platform/graphics/cg/SubimageCacheWithTimer.cpp: 23 (WebCore::SubimageCacheWithTimer::clear): 24 (WebCore::SubimageCacheAdder::translate): 25 (WebCore::SubimageCacheWithTimer::SubimageCacheWithTimer): 26 (WebCore::SubimageCacheWithTimer::pruneCacheTimerFired): 27 (WebCore::SubimageCacheWithTimer::prune): 28 (WebCore::SubimageCacheWithTimer::subimage): 29 (WebCore::SubimageCacheWithTimer::clearImageAndSubimages): 30 (WebCore::SubimageCacheWithTimer::clearAll): 31 (WebCore::SubimageCacheWithTimer::invalidateCacheTimerFired): Deleted. 32 * platform/graphics/cg/SubimageCacheWithTimer.h: 33 1 34 2020-03-23 Stephan Szabo <stephan.szabo@sony.com> 2 35 -
trunk/Source/WebCore/page/cocoa/MemoryReleaseCocoa.mm
r256007 r258908 32 32 #import "LayerPool.h" 33 33 #import "LocaleCocoa.h" 34 #import "SubimageCacheWithTimer.h" 34 35 #import "SystemFontDatabaseCoreText.h" 35 36 #import <notify.h> … … 69 70 #if HAVE(IOSURFACE) 70 71 IOSurfacePool::sharedPool().discardAllSurfaces(); 72 #endif 73 74 #if CACHE_SUBIMAGES 75 SubimageCacheWithTimer::clear(); 71 76 #endif 72 77 } -
trunk/Source/WebCore/platform/graphics/cg/SubimageCacheWithTimer.cpp
r232139 r258908 37 37 SubimageCacheWithTimer* SubimageCacheWithTimer::s_cache; 38 38 39 static const Seconds subimageCacheClearDelay { 1_s }; 39 static const Seconds subimageCachePruneDelay { 500_ms }; 40 static const Seconds subimageCacheEntryLifetime { 500_ms }; 40 41 static const int maxSubimageCacheSize = 300; 41 42 … … 49 50 if (subimageCacheExists()) 50 51 subimageCache().clearImageAndSubimages(image); 52 } 53 54 void SubimageCacheWithTimer::clear() 55 { 56 if (subimageCacheExists()) 57 subimageCache().clearAll(); 51 58 } 52 59 … … 71 78 { 72 79 entry.image = request.image; 80 entry.subimage = adoptCF(CGImageCreateWithImageInRect(request.image, request.rect)); 73 81 entry.rect = request.rect; 74 entry.subimage = adoptCF(CGImageCreateWithImageInRect(request.image, request.rect));75 82 } 76 83 }; 77 84 78 85 SubimageCacheWithTimer::SubimageCacheWithTimer() 79 : m_timer(*this, &SubimageCacheWithTimer:: invalidateCacheTimerFired, subimageCacheClearDelay)86 : m_timer(*this, &SubimageCacheWithTimer::pruneCacheTimerFired) 80 87 { 81 88 } 82 89 83 void SubimageCacheWithTimer:: invalidateCacheTimerFired()90 void SubimageCacheWithTimer::pruneCacheTimerFired() 84 91 { 85 m_images.clear(); 86 m_cache.clear(); 92 prune(); 93 if (m_cache.isEmpty()) { 94 ASSERT(m_imageCounts.isEmpty()); 95 m_timer.stop(); 96 } 97 } 98 99 void SubimageCacheWithTimer::prune() 100 { 101 auto now = MonotonicTime::now(); 102 103 Vector<SubimageCacheEntry> toBeRemoved; 104 105 for (const auto& entry : m_cache) { 106 if ((now - entry.lastAccessTime) > subimageCacheEntryLifetime) 107 toBeRemoved.append(entry); 108 } 109 110 for (auto& entry : toBeRemoved) { 111 m_imageCounts.remove(entry.image.get()); 112 m_cache.remove(entry); 113 } 87 114 } 88 115 89 116 RetainPtr<CGImageRef> SubimageCacheWithTimer::subimage(CGImageRef image, const FloatRect& rect) 90 117 { 91 m_timer.restart(); 118 if (!m_timer.isActive()) 119 m_timer.startRepeating(subimageCachePruneDelay); 120 92 121 if (m_cache.size() == maxSubimageCacheSize) { 93 122 SubimageCacheEntry entry = *m_cache.begin(); 94 m_image s.remove(entry.image.get());123 m_imageCounts.remove(entry.image.get()); 95 124 m_cache.remove(entry); 96 125 } … … 99 128 auto result = m_cache.add<SubimageCacheAdder>(SubimageRequest(image, rect)); 100 129 if (result.isNewEntry) 101 m_image s.add(image);130 m_imageCounts.add(image); 102 131 132 result.iterator->lastAccessTime = MonotonicTime::now(); 103 133 return result.iterator->subimage; 104 134 } … … 106 136 void SubimageCacheWithTimer::clearImageAndSubimages(CGImageRef image) 107 137 { 108 if (m_image s.contains(image)) {138 if (m_imageCounts.contains(image)) { 109 139 Vector<SubimageCacheEntry> toBeRemoved; 110 140 for (const auto& entry : m_cache) { … … 116 146 m_cache.remove(entry); 117 147 118 m_image s.removeAll(image);148 m_imageCounts.removeAll(image); 119 149 } 150 } 151 152 void SubimageCacheWithTimer::clearAll() 153 { 154 m_imageCounts.clear(); 155 m_cache.clear(); 120 156 } 121 157 -
trunk/Source/WebCore/platform/graphics/cg/SubimageCacheWithTimer.h
r241113 r258908 24 24 */ 25 25 26 #ifndef SubimageCacheWithTimer_h 27 #define SubimageCacheWithTimer_h 26 #pragma once 28 27 29 28 #include "FloatRect.h" … … 48 47 struct SubimageCacheEntry { 49 48 RetainPtr<CGImageRef> image; 49 RetainPtr<CGImageRef> subimage; 50 50 FloatRect rect; 51 RetainPtr<CGImageRef> subimage;51 MonotonicTime lastAccessTime; 52 52 }; 53 53 … … 83 83 static RetainPtr<CGImageRef> getSubimage(CGImageRef, const FloatRect&); 84 84 static void clearImage(CGImageRef); 85 static void clear(); 85 86 86 87 private: … … 88 89 89 90 SubimageCacheWithTimer(); 90 void invalidateCacheTimerFired();91 void pruneCacheTimerFired(); 91 92 92 93 RetainPtr<CGImageRef> subimage(CGImageRef, const FloatRect&); 93 94 void clearImageAndSubimages(CGImageRef); 95 void prune(); 96 void clearAll(); 94 97 95 HashCountedSet<CGImageRef> m_image s;98 HashCountedSet<CGImageRef> m_imageCounts; 96 99 SubimageCacheHashSet m_cache; 97 DeferrableOneShotTimer m_timer;100 Timer m_timer; 98 101 99 102 static SubimageCacheWithTimer& subimageCache(); … … 105 108 106 109 } 107 108 #endif // SubimageCacheWithTimer_h
Note: See TracChangeset
for help on using the changeset viewer.