原文地址:http://blogs.msdn.com/b/tess/archive/2006/08/11/695268.aspx

"We use Page.Cache to store temporary data, but we have recently discovered that it causes high memory consumption. The bad thing is that the memory never goes down even though the cache items have expired, and we suspect a possible memory leak in its implementation.

We have created this simple page:

protected void Page_Load(object sender, EventArgs e){
    
this.Page.Cache.Add(Guid.NewGuid().ToString(),
Guid.NewGuid().ToString(), null, DateTime.MaxValue,
TimeSpan.FromMinutes(1),
                                       CacheItemPriority.NotRemovable, new CacheItemRemovedCallback(this.OnRemoved));
}

public void OnRemoved(string key, object value, CacheItemRemovedReason r)
{
          value = null;
}

Which we stress with ACT (Application Center Test) for 5
minutes. Memory usage peaks at 450 MB, and after some time it decreases
to 253 MB, but never goes down completely even though we waited for 10
minutes after the stress test. Our expectation is that the memory should
go down to about 50-60 MB.

The question is does the above scenario fall into the category of memory leaks?"

I had thoroughly enjoyed the quizzes that Rico Mariani and Mike Stall
had on their blogs, so I did a copy cat... and I have to say I really
liked the results, both because I thought the answers were really good
and contained details that I would probably have missed, and also
because it brought up some new questions that I didn't think off.

If you haven't looked at the quiz yet, I would recommend you do, and especially the comments...

Answers/Summary:

Before I start, I want to say that I am not so naive that I claim
that our products are completely bug free, no software ever is... but
when I get a proof and don't agree with the results (especially when it
is such a commonly used feature as Cache) I get as suspicious as Dr.
House:) and start scrutinizing the test.  This is partially why I
brought this question up as a post to begin with... I.e. because I think
it is important that in any situation where you do a stress test or a
proof of concept it is very important that you know the underlying
platform in order to interpret the results correctly.

As I mentioned there were a lot of good comments on the quiz, as
well as many good questions so I will divide the points into different
sections.

1. The CacheItemRemovedCallback
2. The stress test and garbage collection
3. Sliding Expiration and Absolute Expiration 
4. CacheItemPriority.NotRemovable
5. Page.Cache vs. Cache vs. Application
6. Real-life scenario vs. Stress test for Proof
7. A small comment on timers

The CacheItemRemovedCallback

The first thing I noticed when looking at the results given was that
450 MB seemed like an insane amount for this tests.  Even if nothing was
removed from cache, the items stored in cache (GUID's) are relatively
small and would never amount to that much, so something smells very
fishy.  As Matt correctly pointed out in this comment,
we are running into an issue where we are connecting an instance
eventhandler with a cache object, which effectively causes us to cache
the whole page and all its contents.

To get more info about this see my earlier post about "the eventhandlers that made the memory balloon"
In this particular case it is not necessary to set the value to null.
The GUID will be un-rooted when it is removed.  If you have a situation
where you do need to dispose the object that is stored in cache, you
would have to use a static eventhandler of some kind.

Performing this minor change we can get the same stress test to peak
at 50 MB instead of 450, which is a major improvement. But even still
the objects are not removed from memory when the cache expires... so on
to the next point...

The stress test and garbage collection

When doing a stress test like this it is very important to understand
a few things.  The first is how to interpret the results and the second
is to understand the platform we are working with and the behavior of
the garbage collector.

In this case the data that we looked at was memory usage for the
process in taskmanager, alternatively private bytes in performance
monitor.  The question really doesn't tell, but in my private tests I
was looking at private bytes in performance monitor.

What I would be really interested in is
a) are the objects removed properly from cache?
b) does the size of the managed heaps decrease (i.e. are the .net objects stored in cache actually collected)? and
c)
what happens with the size of the process and what will happen if we
run the test a second time, i.e. will it increase by the same amount or
will memory be reused etc.

So I added the counter ASP.NET Apps v2.0.50727/Cache Total Entries,
and saw that it increased gradually with the test, and then every so
often I got a dip that created a sawtooth pattern in the Cache Total
Entries, indicating that cache entries were being released and new ones
came in.  Then i stopped the test and waited, and after 1 minute
(approx.) there was a huge dip, and then after another minute there was
another huge dip, and after about 5 minutes my Cache Total Entries count
was down to 0.

Conclusion #1.  My objects are no longer rooted by the cache and
should be available for garbage collection and removal, but... they are
never collected, why oh why?.

Petros
pointed out that this is because after the stress test, we had no
activity, so nothing caused a GC, and thus nothing will get collected
even if it is available for collection.  This is the most common mistake
when performing a stress test (see my post about why un-rooted objects
are not garbage collected here for more info)

So, what can we do? Well, if i am trying to stress a leak, and want
to verify if it really is a leak, i usually introduce a page with the
following code

GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();

And
run this after the stress test.  Caution!  I wouldn't recommend calling
this in production, just to clean up memory unless you have a really
good reason and can make sure that it is not called so often that it
throws the GC's own mechanism for determining generation limits etc. and
so that it doesn't cause high CPU issues.  Think twice and three and
four times before putting this in production.  It is great for after a
stress test though... to simulate the next time a full GC comes in
without having to create allocations to cause it.

With this in place I could see that my .net CLR Memory/Bytes in all
heaps, went down all the way to 1.5 MB after the collection, which means
that all the objects I cached etc. were gone, and everything was
successful, so we don't have a leak in the Cache mechanism. Yay!!!

Conclusion #2: The objects would have been gone if a full collection would have occurred.

But, wait a minute... my private bytes didn't go down as much as I would have thought... hmmm...

JCornwell
brought up an interesting point... Even if we do collect and the bytes
in all heaps are all nicely down to a minimum, we don't necessarily
decommitt all memory and return it to the OS.  If we had to do this all
the time performance would decrease significantly... but... it is not
really a problem for us, it is just a food for thought when looking at
the results.  See, If I run the same test again, we will reuse this
memory, so it is by no means leaked...

Conclusion #3: It is important to know how the garbage collector
works and what the important counters and values are to correctly
interpret a result.

Sliding Expiration and Absolute Expiration 

No
one touched on this, but I wanted to bring it up because it was
something that caught my eye when I saw the sample.  In this case we had
a sliding expiration of 1 minute and an absolute expiration of
DateTime.MaxValue...

Ok, I have to admit, I don't know all the method signatures and
things by hand but just seeing the sample I was a bit confused about if
the cache items should expire after 1 minute or after whatever insanely
long amount of time DateTime.MaxValue might be.  And I got even more
confused when I looked it up in MSDN
in order to see which took precedence, and found that I was supposed to
have gotten an argument exception if i used both a sliding and absolute
expiration, but I clearly didn't get an exception...

I even got so perturbed that I had to hook up windbg (surprise,
surprise) and make super sure that I didn't get an exception and even
then I didn't trust it...

so I went to the code and found that MaxValue =
Cache.NoAbsoluteExpiration... I later found out that this was documented
in MSDN:) but I had more fun finding it out using reflector.

Soooo... we were using the sliding expiration but I wanted to bring
it up, since it confused me, and perhaps would confuse other people
too...

CacheItemPriority.NotRemovable

This one caused a bit of discussion when Scott
said he thought that it is better to not use NotRemovable and build in
logic to re-populate the cache when needed.  I think it is a good point,
but that NotRemovable has it's benefits too in some cases.

Just to clarify. NotRemovable means that the item will be available
for collection when the cache item has expired but not before. If the
cache item is removable the cache item is eligible for removal
before its expiration if memory usage is high.

One specific location where it has a benefit is in ASP.NET's session
implementation.  As you are probably all aware by now (from my ramblings
in previous posts), InProc session state is stored in cache.  The
session objects are stored with a CacheItemPriority of NotRemovable
since there is no way to repopulate these if they are deleted.   I
believe you should choose CacheItemPriority based on the cost and
possibility of re-populating the cache.  But do feel free to disagree
with me:)

Page.Cache vs. Cache vs. Application

What
I really wanted to get out of the question about the difference between
Page.Cache and Cache was that there really is no difference. They are
pointing to the same object.  The cache is application specific
(appdomain specific), and in the event of an appdomain recycle it is
emptied out.

The Application is very similar to the Cache, in that it is a static
object with a dictionary like structure.  This is saved as a legacy from
ASP, and I have yet to find a reason to use it instead of just using
Cache.

Real-life scenario vs. Stress test for repro.

A
few people mentioned that the test didn't seem realistic. I agree, but I
also don't think the intent of the sample above was to be realistic,
rather I think the person who wrote the email wrote the sample this way
to quickly and easily determine if there was a memory leak, since it is a
lot faster and cleaner than trying to repro with the full application.

A small comment on timers

Finally, I just want to comment on a timers issue that I have mentioned before.

If you run on 1.1. and you see that your cache items aren't expiring (Cache Total Entries) you may be running into this problem http://support.microsoft.com/kb/900822/en-us where timers are not firing properly. But that is not the case in my stress test.

Laters y'all.

Did this blog post help you resolve a problem?

(转载)ASP.NET Quiz Answers: Does Page.Cache leak memory?的更多相关文章

  1. 工作于内存和文件之间的页缓存, Page Cache, the Affair Between Memory and Files

    原文作者:Gustavo Duarte 原文地址:http://duartes.org/gustavo/blog/post/what-your-computer-does-while-you-wait ...

  2. Page Cache, the Affair Between Memory and Files

    Previously we looked at how the kernel manages virtual memory for a user process, but files and I/O ...

  3. Page.Cache

    https://docs.microsoft.com/en-us/dotnet/api/system.web.ui.page.cache?view=netframework-4.8 Gets the ...

  4. Page Cache的落地问题

    除非特别说明,否则本文提到的写操作都是 buffer write/write back. 起因 前几天讨论到一个问题:Linux 下文件 close成功,会不会触发 “刷盘”? 其实这个问题根本不用讨 ...

  5. Linux的page cache使用情况/命中率查看和操控

    转载自宋宝华:https://blog.csdn.net/21cnbao/article/details/80458173 这里总结几个Linux文件缓存(page cache)使用情况.命中率查看的 ...

  6. 从free到page cache

    Free 我们经常用free查看服务器的内存使用情况,而free中的输出却有些让人困惑,如下:   图1-1 先看看各个数字的意义以及如何计算得到: free命令输出的第二行(Mem):这行分别显示了 ...

  7. Page cache和Buffer cache[转1]

    http://www.cnblogs.com/mydomain/archive/2013/02/24/2924707.html Page cache实际上是针对文件系统的,是文件的缓存,在文件层面上的 ...

  8. page cache 与 page buffer 转

    page cache 与 page buffer 标签: cachebuffer磁盘treelinux脚本 2012-05-07 20:47 2905人阅读 评论(0) 收藏 举报  分类: 内核编程 ...

  9. 【转】Linux Page Cache的工作原理

    1 .前言 自从诞生以来,Linux 就被不断完善和普及,目前它已经成为主流通用操作系统之一,使用得非常广泛,它与Windows.UNIX 一起占据了操作系统领域几乎所有的市场份额.特别是在高性能计算 ...

随机推荐

  1. numpy.matlib.randn(标准正态分布)

    #网址 http://docs.scipy.org/doc/numpy/reference/generated/numpy.matlib.randn.html#numpy.matlib.randn n ...

  2. WPF Canvas

    Canvas为容器控件,用于定位. 1.基本应用 <Border HorizontalAlignment="Left" VerticalAlignment="Top ...

  3. 问题:MSChart.exe;结果:微软图表控件MsChart使用方法及各种插件下载地址

    微软图表控件MsChart使用方法及各种插件下载地址 (2012-08-10 17:32:33) 转载▼ 标签: 图表 控件 下载地址 kernel32 微软 it 分类: C# 昨天在网上看到了微软 ...

  4. WSGI 简介(使用python描述)

    WSGI 简介 背景 Python Web 开发中,服务端程序可以分为两个部分,一是服务器程序,二是应用程序.前者负责把客户端请求接收,整理,后者负责具体的逻辑处理.为了方便应用程序的开发,我们把常用 ...

  5. 菜鸟攻城狮2(JAVA开发环境)

    1.JDK下载路径:www.oracle.com/technetwork/java/javase/downloads 2.安装案例:最后一步认证操作 win+R 或者 点击开始--〉运行 输入“cmd ...

  6. 关于login/interactive/no-interactive shell和profile/bash_profile/bashrc

    login shell:第一次登录进系统时的shell,一般是指本机启动时的控制台shell或者ssh远程登录时的shell. interactive shell:登录以后,再打开控制台时运行的she ...

  7. 怀旧系列(3)----Pascal

    Pascal语言是高中时代2000年左右为了参加计算机竞赛学习的一门语言(Turbo Pascal7.0).据说这么语言的结构化非常好,非常适合青少年形成一定的编程思想.但是现在的角度想想都是扯淡,现 ...

  8. 8.使用hydra对端口进行爆破

    如果对开启端口的服务不清楚,请看我之前写的文章:https://www.cnblogs.com/bmjoker/p/8833316.html 2018,网站的防护(sql,xss...)的安全保护也已 ...

  9. JAVA IO包的整理---------Writer和Reader

    一 Writer public abstract class Writer extends Object implements Appendable, Closeable, Flushable 这个类 ...

  10. Windows10安装node.js,vue.js以及创建第一个vue.js项目

    [工具官网] Node.js : http://nodejs.cn/ 淘宝NPM: https://npm.taobao.org/ 一.安装环境 1.本机系统:Windows 10 Pro(64位)2 ...