MemoryCache module is a part of the bigger mechanism responsible for page loading called loader. You can learn more about loader from this article (https://www.webkit.org/blog/427/webkit-page-cache-i-the-basics/). This article focuses only on Memory Cache aspects and its internal components without interaction with loader.
This cache holds subresources used by Web pages: images, scripts, stylesheets, etc. The cache keeps a flexible but bounded window of dead resources that grows/shrinks depending on the live resource load. Here's an example of cache growth over time, with a min dead resource capacity of 25% and a max dead resource capacity of 50%: |-----| Dead: - |----------| Live: + --|----------| Cache boundary: | (objects outside this mark have been evicted) --|----------++++++++++| -------|-----+++++++++++++++| -------|-----+++++++++++++++|+++++ The behavior of the cache changes in the following way if shouldMakeResourcePurgeableOnEviction returns true. 1. Dead resources in the cache are kept in non-purgeable memory. 2. When we prune dead resources, instead of freeing them, we mark their memory as purgeable and keep the resources until the kernel reclaims the purgeable memory. By leaving the in-cache dead resources in dirty resident memory, we decrease the likelihood of the kernel claiming that memory and forcing us to refetch the resource (for example when a user presses back). And by having an unbounded number of resource objects using purgeable memory, we can use as much memory as it is available on the machine. The trade-off here is that the CachedResource object (and its member variables) are allocated in non-purgeable TC-malloc'd memory so we would see slightly more memory use due to this.
What exactly means that some memory is purgeable/non-purgeable? Well, some operating systems allows to mark memory as purgeable. It means that since it is marked the content may disappear (the system expropriatse it) at any point of time (until it gets unmarked) without informing the application. So the application may know if the memory is purged after it asks the system for the resource (this may be implemented differently on separate systems). This leads to serious consequences in object life cycle management:
- this kind of memory disallows to store objects that depends on its (or related by inheritance/consistency) destructor
- ownership/references to the memory should never be passed to the modules that wouldn't treat this memory as a “special object”.
- known and widely used techniques of managing object lifetime (like smart pointers) are not relevant to objects stored in purgable memory
This class is designed to store and manage objects (web resources) lifecycle. Stored resources may be live or dead. A resource is dead when there are no references from web pages. And vice versa resource is live when there is at least one reference to it from web page.
MemoryCache client may have influence on RAM usage using three values:
- min dead bytes - minimum size of dead resources when purging
- max dead bytes - maximum size of dead resources when purging
- total capacity bytes - sum of live and dead resources capacity sizes
Prune procedure provides one more mechanism to reduce memory consumption. In the beginning of this article I've mentioned about quaint technique - purgeable memory. CachedResource has ability to move stored raw data to special buffer called PurgeableBuffer. Since data is located in such buffer the operating system may take over (purge) memory allocated for it. So if a resource buffer was purged the prune procedure would also remove all CachedResource data related to the buffer - it's called eviction. Evict will also remove a resource from MemoryCache internal structures and after that the only way to restore lost data is to regain it basing on related ResourceRequest.
MemoryCache keeps references to resources in three different structures:
- m_resources - a LRU-based map of all resources kept in cache
- m_allResources - Vector of LRU lists with fixed size (32). Basing on CachedResource access counter a resource is located in appropriate list. Prune procedure will start evict beginning from last recently used resources.
- m_liveDecodedResources - live resources with decoded data. If stored resources significantly exceeds total capacity MemoryCache tries to remove decoded data one by one until boundary assumptions will be fulfilled or there would be nothing redundant data to release.