void MemoryCache::dumpLRULists(bool includeLive) const { printf("LRU-SP lists in eviction order (Kilobytes decoded, Kilobytes encoded, Access count, Referenced, isPurgeable, wasPurged):\n"); int size = m_allResources.size(); for (int i = size - 1; i >= 0; i--) { printf("\n\nList %d: ", i); CachedResource* current = m_allResources[i].m_tail; while (current) { CachedResource* prev = current->m_prevInAllResourcesList; if (includeLive || !current->hasClients()) printf("(%.1fK, %.1fK, %uA, %dR, %d, %d); ", current->decodedSize() / 1024.0f, (current->encodedSize() + current->overheadSize()) / 1024.0f, current->accessCount(), current->hasClients(), current->isPurgeable(), current->wasPurged()); current = prev; } } }
void MemoryCache::pruneDeadResourcesToSize(unsigned targetSize) { if (m_inPruneResources) return; TemporaryChange<bool> reentrancyProtector(m_inPruneResources, true); int size = m_allResources.size(); // See if we have any purged resources we can evict. for (int i = 0; i < size; i++) { CachedResource* current = m_allResources[i].m_tail; while (current) { CachedResource* prev = current->m_prevInAllResourcesList; if (current->wasPurged()) { ASSERT(!current->hasClients()); ASSERT(!current->isPreloaded()); evict(current); } current = prev; } } if (targetSize && m_deadSize <= targetSize) return; bool canShrinkLRULists = true; for (int i = size - 1; i >= 0; i--) { // Remove from the tail, since this is the least frequently accessed of the objects. CachedResource* current = m_allResources[i].m_tail; // First flush all the decoded data in this queue. while (current) { // Protect 'previous' so it can't get deleted during destroyDecodedData(). CachedResourceHandle<CachedResource> previous = current->m_prevInAllResourcesList; ASSERT(!previous || previous->inCache()); if (!current->hasClients() && !current->isPreloaded() && current->isLoaded()) { // Destroy our decoded data. This will remove us from // m_liveDecodedResources, and possibly move us to a different // LRU list in m_allResources. current->destroyDecodedData(); if (targetSize && m_deadSize <= targetSize) return; } // Decoded data may reference other resources. Stop iterating if 'previous' somehow got // kicked out of cache during destroyDecodedData(). if (previous && !previous->inCache()) break; current = previous.get(); } // Now evict objects from this queue. current = m_allResources[i].m_tail; while (current) { CachedResourceHandle<CachedResource> previous = current->m_prevInAllResourcesList; ASSERT(!previous || previous->inCache()); if (!current->hasClients() && !current->isPreloaded() && !current->isCacheValidator()) { if (!makeResourcePurgeable(current)) evict(current); if (targetSize && m_deadSize <= targetSize) return; } if (previous && !previous->inCache()) break; current = previous.get(); } // Shrink the vector back down so we don't waste time inspecting // empty LRU lists on future prunes. if (m_allResources[i].m_head) canShrinkLRULists = false; else if (canShrinkLRULists) m_allResources.resize(i); } }