I'm trying to dispose of an object when the system is low on memory - is there a better way than this?

寵の児 提交于 2020-01-06 11:24:09

问题


What I am doing currently is adding an item to the Cache and disposing of my object when that object is removed from the Cache. The logic being that it gets removed when memory consumption gets too high. I'm open to outher suggestions but I would like to avoid creating a thread than continually measures memory statistics if possible. Here is my code:

public class WebServiceCache : ConcurrentDictionary<string, WebServiceCacheObject>, IDisposable
{
    private WebServiceCache()
    {
        if (HttpContext.Current != null && HttpContext.Current.Cache != null)
        {
            HttpContext.Current.Cache.Add("CacheTest", true, null, DateTime.Now.AddYears(1), System.Web.Caching.Cache.NoSlidingExpiration, 
                System.Web.Caching.CacheItemPriority.Low, 
                (key, obj, reason) => {
                    if (reason != System.Web.Caching.CacheItemRemovedReason.Removed)
                    {
                        WebServiceCache.Current.ClearCache(50);
                    }
                });
        }
    }

    private static WebServiceCache _current;
    public static WebServiceCache Current
    {
        get
        {
            if (_current != null && _current.IsDisposed)
            {
                // Might as well clear it fully
                _current = null;
            }
            if (_current == null)
            {
                _current = new WebServiceCache();
            }
            return _current;
        }
    }


    public void ClearCache(short percentage)
    {
        try
        {
            if (percentage == 100)
            {
                this.Dispose();
                return;
            }
            var oldest = _current.Min(c => c.Value.LastAccessed);
            var newest = _current.Max(c => c.Value.LastAccessed);
            var difference = (newest - oldest).TotalSeconds;
            var deleteBefore = oldest.AddSeconds((difference / 100) * percentage);
            // LINQ doesn't seem to work very well on concurrent dictionaries
            //var toDelete = _current.Where(c => DateTime.Compare(c.Value.LastAccessed,deleteBefore) < 0);
            var keys = _current.Keys.ToArray();
            foreach (var key in keys)
            {
                if (DateTime.Compare(_current[key].LastAccessed, deleteBefore) < 0)
                {
                    WebServiceCacheObject tmp;
                    _current.TryRemove(key, out tmp);
                    tmp = null;
                }
            }
            keys = null;
        }
        catch
        {
            // If we throw an exception here then we are probably really low on memory
            _current = null;
            GC.Collect();
        }
    }

    public bool IsDisposed { get; set; }
    public void Dispose()
    {
        this.Clear();
        HttpContext.Current.Cache.Remove("CacheTest");
        this.IsDisposed = true;
    }
}

In Global.asax

    void context_Error(object sender, EventArgs e)
    {
        Exception ex = _context.Server.GetLastError();
        if (ex.InnerException is OutOfMemoryException)
        {
            if (_NgageWebControls.classes.Caching.WebServiceCache.Current != null)
            {
                _NgageWebControls.classes.Caching.WebServiceCache.Current.ClearCache(100);
            }
        }
    }

Thanks,

Joe


回答1:


You can access the ASP.NET Cache from anywhere in your application as the static property:

HttpRuntime.Cache

You don't need to be in the context of a Request (i.e. don't need HttpContext.Current) to do this.

So you should be using it instead of rolling your own caching solution.



来源:https://stackoverflow.com/questions/17488759/im-trying-to-dispose-of-an-object-when-the-system-is-low-on-memory-is-there-a

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!