OLD | NEW |
---|---|
1 /* | 1 /* |
2 Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de) | 2 Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de) |
3 Copyright (C) 2001 Dirk Mueller (mueller@kde.org) | 3 Copyright (C) 2001 Dirk Mueller (mueller@kde.org) |
4 Copyright (C) 2002 Waldo Bastian (bastian@kde.org) | 4 Copyright (C) 2002 Waldo Bastian (bastian@kde.org) |
5 Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. | 5 Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. |
6 | 6 |
7 This library is free software; you can redistribute it and/or | 7 This library is free software; you can redistribute it and/or |
8 modify it under the terms of the GNU Library General Public | 8 modify it under the terms of the GNU Library General Public |
9 License as published by the Free Software Foundation; either | 9 License as published by the Free Software Foundation; either |
10 version 2 of the License, or (at your option) any later version. | 10 version 2 of the License, or (at your option) any later version. |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
45 #include "wtf/TemporaryChange.h" | 45 #include "wtf/TemporaryChange.h" |
46 #include "wtf/text/CString.h" | 46 #include "wtf/text/CString.h" |
47 | 47 |
48 using namespace std; | 48 using namespace std; |
49 | 49 |
50 namespace WebCore { | 50 namespace WebCore { |
51 | 51 |
52 static MemoryCache* gMemoryCache; | 52 static MemoryCache* gMemoryCache; |
53 | 53 |
54 static const int cDefaultCacheCapacity = 8192 * 1024; | 54 static const int cDefaultCacheCapacity = 8192 * 1024; |
55 static const double cMinDelayBeforeLiveDecodedPrune = 1; // Seconds. | |
Justin Novosad
2013/07/23 16:55:12
This variable should still exist, but it should be
| |
56 static const float cTargetPrunePercentage = .95f; // Percentage of capacity towa rd which we prune, to avoid immediately pruning again. | 55 static const float cTargetPrunePercentage = .95f; // Percentage of capacity towa rd which we prune, to avoid immediately pruning again. |
57 static const double cDefaultDecodedDataDeletionInterval = 0; | 56 static const double cDefaultDecodedDataDeletionInterval = 0; |
58 | 57 |
59 MemoryCache* memoryCache() | 58 MemoryCache* memoryCache() |
60 { | 59 { |
61 ASSERT(WTF::isMainThread()); | 60 ASSERT(WTF::isMainThread()); |
62 if (!gMemoryCache) | 61 if (!gMemoryCache) |
63 gMemoryCache = new MemoryCache(); | 62 gMemoryCache = new MemoryCache(); |
64 return gMemoryCache; | 63 return gMemoryCache; |
65 } | 64 } |
66 | 65 |
67 void setMemoryCacheForTesting(MemoryCache* memoryCache) | 66 void setMemoryCacheForTesting(MemoryCache* memoryCache) |
68 { | 67 { |
69 gMemoryCache = memoryCache; | 68 gMemoryCache = memoryCache; |
70 } | 69 } |
71 | 70 |
72 MemoryCache::MemoryCache() | 71 MemoryCache::MemoryCache() |
73 : m_inPruneResources(false) | 72 : m_inPruneResources(false) |
74 , m_capacity(cDefaultCacheCapacity) | 73 , m_capacity(cDefaultCacheCapacity) |
75 , m_minDeadCapacity(0) | 74 , m_minDeadCapacity(0) |
76 , m_maxDeadCapacity(cDefaultCacheCapacity) | 75 , m_maxDeadCapacity(cDefaultCacheCapacity) |
77 , m_deadDecodedDataDeletionInterval(cDefaultDecodedDataDeletionInterval) | 76 , m_deadDecodedDataDeletionInterval(cDefaultDecodedDataDeletionInterval) |
78 , m_liveSize(0) | 77 , m_liveSize(0) |
79 , m_deadSize(0) | 78 , m_deadSize(0) |
79 , m_delayBeforeLiveDecodedPrune(1) // Seconds. | |
80 #ifdef MEMORY_CACHE_STATS | 80 #ifdef MEMORY_CACHE_STATS |
81 , m_statsTimer(this, &MemoryCache::dumpStats) | 81 , m_statsTimer(this, &MemoryCache::dumpStats) |
82 #endif | 82 #endif |
83 { | 83 { |
84 #ifdef MEMORY_CACHE_STATS | 84 #ifdef MEMORY_CACHE_STATS |
85 const double statsIntervalInSeconds = 15; | 85 const double statsIntervalInSeconds = 15; |
86 m_statsTimer.startRepeating(statsIntervalInSeconds); | 86 m_statsTimer.startRepeating(statsIntervalInSeconds); |
87 #endif | 87 #endif |
88 } | 88 } |
89 | 89 |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
179 { | 179 { |
180 if (m_inPruneResources) | 180 if (m_inPruneResources) |
181 return; | 181 return; |
182 TemporaryChange<bool> reentrancyProtector(m_inPruneResources, true); | 182 TemporaryChange<bool> reentrancyProtector(m_inPruneResources, true); |
183 | 183 |
184 double currentTime = FrameView::currentPaintTimeStamp(); | 184 double currentTime = FrameView::currentPaintTimeStamp(); |
185 if (!currentTime) // In case prune is called directly, outside of a Frame pa int. | 185 if (!currentTime) // In case prune is called directly, outside of a Frame pa int. |
186 currentTime = WTF::currentTime(); | 186 currentTime = WTF::currentTime(); |
187 | 187 |
188 // Destroy any decoded data in live objects that we can. | 188 // Destroy any decoded data in live objects that we can. |
189 // Start from the tail, since this is the least recently accessed of the obj ects. | 189 // Start from the tail, since this is the lowest priority |
190 // and least recently accessed of the objects. | |
190 | 191 |
191 // The list might not be sorted by the m_lastDecodedAccessTime. The impact | 192 // The list might not be sorted by the m_lastDecodedAccessTime. The impact |
192 // of this weaker invariant is minor as the below if statement to check the | 193 // of this weaker invariant is minor as the below if statement to check the |
193 // elapsedTime will evaluate to false as the currentTime will be a lot | 194 // elapsedTime will evaluate to false as the currentTime will be a lot |
194 // greater than the current->m_lastDecodedAccessTime. | 195 // greater than the current->m_lastDecodedAccessTime. |
195 // For more details see: https://bugs.webkit.org/show_bug.cgi?id=30209 | 196 // For more details see: https://bugs.webkit.org/show_bug.cgi?id=30209 |
196 CachedResource* current = m_liveDecodedResources.m_tail; | |
197 while (current) { | |
198 CachedResource* prev = current->m_prevInLiveResourcesList; | |
199 ASSERT(current->hasClients()); | |
200 if (current->isLoaded() && current->decodedSize()) { | |
201 // Check to see if the remaining resources are too new to prune. | |
202 double elapsedTime = currentTime - current->m_lastDecodedAccessTime; | |
203 if (elapsedTime < cMinDelayBeforeLiveDecodedPrune) | |
204 return; | |
205 | 197 |
206 // Destroy our decoded data. This will remove us from | 198 // Start pruning from the lowest priority list. |
207 // m_liveDecodedResources, and possibly move us to a different LRU | 199 for (int i = 0; i < 3; i++) { |
208 // list in m_allResources. | 200 CachedResource* current = m_liveDecodedResources[i].m_tail; |
209 current->destroyDecodedData(); | 201 while (current) { |
202 CachedResource* prev = current->m_prevInLiveResourcesList; | |
203 ASSERT(current->hasClients()); | |
204 if (current->isLoaded() && current->decodedSize()) { | |
205 // Check to see if the remaining resources are too new to prune. | |
206 double elapsedTime = currentTime - current->m_lastDecodedAccessT ime; | |
207 if (elapsedTime < m_delayBeforeLiveDecodedPrune) | |
208 return; | |
210 | 209 |
211 if (targetSize && m_liveSize <= targetSize) | 210 // Destroy our decoded data. This will remove us from |
212 return; | 211 // m_liveDecodedResources, and possibly move us to a different L RU |
212 // list in m_allResources. | |
213 current->destroyDecodedData(); | |
214 | |
215 if (targetSize && m_liveSize <= targetSize) | |
216 return; | |
217 } | |
218 current = prev; | |
213 } | 219 } |
214 current = prev; | |
215 } | 220 } |
216 } | 221 } |
217 | 222 |
218 void MemoryCache::pruneDeadResources() | 223 void MemoryCache::pruneDeadResources() |
219 { | 224 { |
220 unsigned capacity = deadCapacity(); | 225 unsigned capacity = deadCapacity(); |
221 if (capacity && m_deadSize <= capacity) | 226 if (capacity && m_deadSize <= capacity) |
222 return; | 227 return; |
223 | 228 |
224 unsigned targetSize = static_cast<unsigned>(capacity * cTargetPrunePercentag e); // Cut by a percentage to avoid immediately pruning again. | 229 unsigned targetSize = static_cast<unsigned>(capacity * cTargetPrunePercentag e); // Cut by a percentage to avoid immediately pruning again. |
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
432 | 437 |
433 } | 438 } |
434 | 439 |
435 void MemoryCache::removeFromLiveDecodedResourcesList(CachedResource* resource) | 440 void MemoryCache::removeFromLiveDecodedResourcesList(CachedResource* resource) |
436 { | 441 { |
437 // If we've never been accessed, then we're brand new and not in any list. | 442 // If we've never been accessed, then we're brand new and not in any list. |
438 if (!resource->m_inLiveDecodedResourcesList) | 443 if (!resource->m_inLiveDecodedResourcesList) |
439 return; | 444 return; |
440 resource->m_inLiveDecodedResourcesList = false; | 445 resource->m_inLiveDecodedResourcesList = false; |
441 | 446 |
447 LRUList* list = &m_liveDecodedResources[resource->decodePriority()]; | |
448 | |
442 #if !ASSERT_DISABLED | 449 #if !ASSERT_DISABLED |
443 // Verify that we are in fact in this list. | 450 // Verify that we are in fact in this list. |
444 bool found = false; | 451 bool found = false; |
445 for (CachedResource* current = m_liveDecodedResources.m_head; current; curre nt = current->m_nextInLiveResourcesList) { | 452 for (CachedResource* current = list->m_head; current; current = current->m_n extInLiveResourcesList) { |
446 if (current == resource) { | 453 if (current == resource) { |
447 found = true; | 454 found = true; |
448 break; | 455 break; |
449 } | 456 } |
450 } | 457 } |
451 ASSERT(found); | 458 ASSERT(found); |
452 #endif | 459 #endif |
453 | 460 |
454 CachedResource* next = resource->m_nextInLiveResourcesList; | 461 CachedResource* next = resource->m_nextInLiveResourcesList; |
455 CachedResource* prev = resource->m_prevInLiveResourcesList; | 462 CachedResource* prev = resource->m_prevInLiveResourcesList; |
456 | 463 |
457 if (next == 0 && prev == 0 && m_liveDecodedResources.m_head != resource) | 464 if (!next && !prev && list->m_head != resource) |
458 return; | 465 return; |
459 | 466 |
460 resource->m_nextInLiveResourcesList = 0; | 467 resource->m_nextInLiveResourcesList = 0; |
461 resource->m_prevInLiveResourcesList = 0; | 468 resource->m_prevInLiveResourcesList = 0; |
462 | 469 |
463 if (next) | 470 if (next) |
464 next->m_prevInLiveResourcesList = prev; | 471 next->m_prevInLiveResourcesList = prev; |
465 else if (m_liveDecodedResources.m_tail == resource) | 472 else if (list->m_tail == resource) |
466 m_liveDecodedResources.m_tail = prev; | 473 list->m_tail = prev; |
467 | 474 |
468 if (prev) | 475 if (prev) |
469 prev->m_nextInLiveResourcesList = next; | 476 prev->m_nextInLiveResourcesList = next; |
470 else if (m_liveDecodedResources.m_head == resource) | 477 else if (list->m_head == resource) |
471 m_liveDecodedResources.m_head = next; | 478 list->m_head = next; |
472 } | 479 } |
473 | 480 |
474 void MemoryCache::insertInLiveDecodedResourcesList(CachedResource* resource) | 481 void MemoryCache::insertInLiveDecodedResourcesList(CachedResource* resource) |
475 { | 482 { |
476 // Make sure we aren't in the list already. | 483 // Make sure we aren't in the list already. |
477 ASSERT(!resource->m_nextInLiveResourcesList && !resource->m_prevInLiveResour cesList && !resource->m_inLiveDecodedResourcesList); | 484 ASSERT(!resource->m_nextInLiveResourcesList && !resource->m_prevInLiveResour cesList && !resource->m_inLiveDecodedResourcesList); |
478 resource->m_inLiveDecodedResourcesList = true; | 485 resource->m_inLiveDecodedResourcesList = true; |
479 | 486 |
480 resource->m_nextInLiveResourcesList = m_liveDecodedResources.m_head; | 487 LRUList* list = &m_liveDecodedResources[resource->decodePriority()]; |
481 if (m_liveDecodedResources.m_head) | 488 resource->m_nextInLiveResourcesList = list->m_head; |
482 m_liveDecodedResources.m_head->m_prevInLiveResourcesList = resource; | 489 if (list->m_head) |
483 m_liveDecodedResources.m_head = resource; | 490 list->m_head->m_prevInLiveResourcesList = resource; |
484 | 491 list->m_head = resource; |
492 | |
485 if (!resource->m_nextInLiveResourcesList) | 493 if (!resource->m_nextInLiveResourcesList) |
486 m_liveDecodedResources.m_tail = resource; | 494 list->m_tail = resource; |
487 | 495 |
488 #if !ASSERT_DISABLED | 496 #if !ASSERT_DISABLED |
489 // Verify that we are in now in the list like we should be. | 497 // Verify that we are in now in the list like we should be. |
490 bool found = false; | 498 bool found = false; |
491 for (CachedResource* current = m_liveDecodedResources.m_head; current; curre nt = current->m_nextInLiveResourcesList) { | 499 for (CachedResource* current = list->m_head; current; current = current->m_n extInLiveResourcesList) { |
492 if (current == resource) { | 500 if (current == resource) { |
493 found = true; | 501 found = true; |
494 break; | 502 break; |
495 } | 503 } |
496 } | 504 } |
497 ASSERT(found); | 505 ASSERT(found); |
498 #endif | 506 #endif |
499 | 507 |
500 } | 508 } |
501 | 509 |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
582 } | 590 } |
583 return stats; | 591 return stats; |
584 } | 592 } |
585 | 593 |
586 void MemoryCache::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const | 594 void MemoryCache::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const |
587 { | 595 { |
588 MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::MemoryCache Structures); | 596 MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::MemoryCache Structures); |
589 memoryObjectInfo->setClassName("MemoryCache"); | 597 memoryObjectInfo->setClassName("MemoryCache"); |
590 info.addMember(m_resources, "resources"); | 598 info.addMember(m_resources, "resources"); |
591 info.addMember(m_allResources, "allResources"); | 599 info.addMember(m_allResources, "allResources"); |
592 info.addMember(m_liveDecodedResources, "liveDecodedResources"); | 600 for (int i = 0; i < 3; ++i) |
601 info.addMember(m_liveDecodedResources[i], "liveDecodedResources"); | |
593 for (CachedResourceMap::const_iterator i = m_resources.begin(); i != m_resou rces.end(); ++i) | 602 for (CachedResourceMap::const_iterator i = m_resources.begin(); i != m_resou rces.end(); ++i) |
594 info.addMember(i->value, "cachedResourceItem", WTF::RetainingPointer); | 603 info.addMember(i->value, "cachedResourceItem", WTF::RetainingPointer); |
595 } | 604 } |
596 | 605 |
597 void MemoryCache::evictResources() | 606 void MemoryCache::evictResources() |
598 { | 607 { |
599 for (;;) { | 608 for (;;) { |
600 CachedResourceMap::iterator i = m_resources.begin(); | 609 CachedResourceMap::iterator i = m_resources.begin(); |
601 if (i == m_resources.end()) | 610 if (i == m_resources.end()) |
602 break; | 611 break; |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
658 printf("(%.1fK, %.1fK, %uA, %dR, %d, %d); ", current->decodedSiz e() / 1024.0f, (current->encodedSize() + current->overheadSize()) / 1024.0f, cur rent->accessCount(), current->hasClients(), current->isPurgeable(), current->was Purged()); | 667 printf("(%.1fK, %.1fK, %uA, %dR, %d, %d); ", current->decodedSiz e() / 1024.0f, (current->encodedSize() + current->overheadSize()) / 1024.0f, cur rent->accessCount(), current->hasClients(), current->isPurgeable(), current->was Purged()); |
659 | 668 |
660 current = prev; | 669 current = prev; |
661 } | 670 } |
662 } | 671 } |
663 } | 672 } |
664 | 673 |
665 #endif // MEMORY_CACHE_STATS | 674 #endif // MEMORY_CACHE_STATS |
666 | 675 |
667 } // namespace WebCore | 676 } // namespace WebCore |
OLD | NEW |