none
MemoryCache grows indefinitely RRS feed

  • Question

  • Hi,

    I have a problem with MemoryCache.

    It seems that memory limits are not respected.

    I try to add to the web.config file, but it has no effect:

    <system.runtime.caching>
        <memoryCache>
          <namedCaches>
            <add name="Default" cacheMemoryLimitMegabytes="100" physicalMemoryLimitPercentage="10" pollingInterval="00:00:05" />
          </namedCaches>
        </memoryCache>
      </system.runtime.caching>  

    Looking at the Task Manager I can see Memoty usage up to 1GB of RAM (16GB on my PC).

    Any idea?

    Tuesday, April 17, 2018 1:12 PM

Answers

  • Unfortunately I have to work with Framework 4.6.1 that does not support GetLastSizeMethod.

    I tried your code, it worked and finally I found the problem.

    I a SQLChangeMonitor (with SQLDependency) attacched to the policy of my cache.

    It's the Monitor that prevent the cache from cleaning...

    I removed the monitor and I'm trying to invalidate the cache in other ways when database changes.

    • Marked as answer by Nazza Thursday, April 26, 2018 10:01 AM
    Thursday, April 19, 2018 1:02 PM

All replies

  • Couple of things. Firstly the name attribute should be "default", not "Default". I don't know if the reader logic cares about case in cache names or not but I suspect it isn't applying anything.

    You said memory usage was 1GB but is that for your entire app or just the cache itself? How are you measuring the cache itself? You set a limit of 10% so 10% of 16GB is 1.6 GB so you'd still have some room to grow.

    You are also specifying a fixed limit. I'm not sure which one takes precedence when you set both. It could be the lesser of the 2 or the greater. The documentation doesn't say.


    Michael Taylor http://www.michaeltaylorp3.net

    Tuesday, April 17, 2018 1:53 PM
    Moderator
  • Hello Nazza,

    Check the below link.

    <memorycache>Element (Cache Settings)</memorycache>

    Attribute Description
    CacheMemoryLimitMegabytes The maximum memory size, in megabytes, that an instance of a MemoryCache object can grow to. The default value is 0, which means that the MemoryCache class's autosize heuristics are used by default.
    Name The name of the cache configuration.
    PhysicalMemoryLimitPercentage The percentage of physical memory that can be used by the cache. The default value is 0, which means that the MemoryCache class's autosize heuristics are used by default.
    PollingInterval A value that indicates the time interval after which the cache implementation compares the current memory load against the absolute and percentage-based memory limits that are set for the cache instance. The value is entered in "HH:MM:SS" format.

    Best Regards,

    Neil Hu


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Wednesday, April 18, 2018 2:07 AM
    Moderator
  • Couple of things. Firstly the name attribute should be "default", not "Default". I don't know if the reader logic cares about case in cache names or not but I suspect it isn't applying anything.

    You said memory usage was 1GB but is that for your entire app or just the cache itself? How are you measuring the cache itself? You set a limit of 10% so 10% of 16GB is 1.6 GB so you'd still have some room to grow.

    You are also specifying a fixed limit. I'm not sure which one takes precedence when you set both. It could be the lesser of the 2 or the greater. The documentation doesn't say.


    Michael Taylor http://www.michaeltaylorp3.net

    I have modified my web.config

    <add name="default" cacheMemoryLimitMegabytes="800" physicalMemoryLimitPercentage="5" pollingInterval="00:00:05" />

    the cache grows further 800MB.

    I monitor it with Task Manager and Visual Studio diagnostic monitor.

    Wednesday, April 18, 2018 9:19 AM
  • Task Manager cannot see how much space MemoryCache is using. It can only see process level memory. That isn't going to be an accurate representation.

    Doing a quick test, it does appear the docs are wrong. The name in the config needs to be Default otherwise the default cache won't use it. I'd recommend you provide feedback to the docs team to correct it and clarify that it is case sensitive. You can confirm the cache is using the right settings by looking at the properties.

    I did a quick test in a console app and I can see the behavior you're describing but that isn't adding up. GetLastSize is returning 0 each time although there is data there. However if you call Trim(0) then it does trim the cache which leads me to believe there is something missing. I'll have to do a little more research.

    As a side note, MemoryCache is the ASP.NET Cache type modified to work with non-web apps. Really for ASP.NET you should just use Cache which is already exposed to you. 


    Michael Taylor http://www.michaeltaylorp3.net

    Wednesday, April 18, 2018 2:27 PM
    Moderator
  • OK, I've done more research and it does appear to be working correctly. Under the hood the MemoryCacheStatistics instance gets set up on creation of the cache. This type sets up a timer (based upon the polling) to automatically trim the cache. While you may be able to add more than the cache allows, it will eventually trim out the excess. 

    Here's a simple example.

    static void Main ( string[] args )
    {
        var cache = MemoryCache.Default;                                  
                            
        // 8K * 10000 = 80MB
        for (var index = 0; index < 10000; ++index)
        {
            //8 * 1,000 = 8,000
            cache.Add($"Key_{index}", new double[1,000], DateTime.Now.AddHours(5));
        };
    
        var totalItems = cache.Count();
    
        var terminate = new ManualResetEvent(false);
    
        Console.CancelKeyPress += ( o, e ) => terminate.Set();
    
        while (!terminate.WaitOne(2000))
        {
            Console.WriteLine($"Size = {cache.GetLastSize()}, Count = {cache.Count()}");
        };
    }

    The cache is first filled with more than enough data to overflow the cache. Then the program polls indefinitely checking the count of the cache. After about 5 seconds the cache should drop down in count as it is trimmed.

    An important side note of the cache. This doesn't trigger a GC so even though the cache removes the item the underlying memory won't get cleaned up until the GC runs later.


    Michael Taylor http://www.michaeltaylorp3.net

    Wednesday, April 18, 2018 2:43 PM
    Moderator
  • Unfortunately I have to work with Framework 4.6.1 that does not support GetLastSizeMethod.

    I tried your code, it worked and finally I found the problem.

    I a SQLChangeMonitor (with SQLDependency) attacched to the policy of my cache.

    It's the Monitor that prevent the cache from cleaning...

    I removed the monitor and I'm trying to invalidate the cache in other ways when database changes.

    • Marked as answer by Nazza Thursday, April 26, 2018 10:01 AM
    Thursday, April 19, 2018 1:02 PM
  • Hello Nazza,

    >>I tried your code, it worked and finally I found the problem.

    I'm glad that you have solved the issues. And you could mark your reply as answer if the issue has been solved. This can be beneficial to other members they are under the same circumstance. And if you have any concerns, please do not hesitate to let us know.

    Best regards,

    Neil Hu


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Wednesday, April 25, 2018 7:12 AM
    Moderator