原文地址: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. C语言32关键字

    关键字 说明 auto 声明自动变量 short 声明短整型变量或函数 int 声明整型变量或函数 long 声明长整型变量或函数 float 声明浮点型变量或函数 double 声明双精度变量或函数 ...

  2. [51nod1212]最小生成树模板

    解题关键:注意下标 解法一:prim算法 #include<bits/stdc++.h> #define maxv 1002 #define maxm 50002 #define INF ...

  3. java中的几种架构对象(PO,VO,DAO,BO,POJO)

    java中的几种对象(PO,VO,DAO,BO,POJO)   一.PO :(persistant object ),持久对象 可以看成是与数据库中的表相映射的java对象.使用Hibernate来生 ...

  4. ubuntu-12.04.5安装cacti笔记

    坑啊,磨磨蹭蹭按了一个星期.按了3个版本. 第一次:cacti-0.8.7e.tar.gz 安装完之后,Host: Localhost->Memory Usage...四张图始终出不了.点击进去 ...

  5. hdu1099

    #include<iostream> using namespace std; __int64 gcd(__int64 a,__int64 b) { return b?gcd(b,a%b) ...

  6. IOS 完成来电归属地

    首先是一个库:(有时间在上传) 然后设置一个工具类 .h @interface HMFoundLocation : NSObject AS_SINGLETON(HMFoundLocation) @pr ...

  7. 《Linux内核设计与实现》读书笔记(一)-内核简介

    本篇简单介绍内核相关的基本概念. 主要内容: 单内核和微内核 内核版本号 1. 单内核和微内核   原理 优势 劣势 单内核 整个内核都在一个大内核地址空间上运行. 1. 简单.2. 高效:所有内核都 ...

  8. nkv客户端性能调优

    此文已由作者张洪箫授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 问题描述 随着考拉业务的增长和规模的扩大,很多的应用都开始重度依赖缓存服务,也就是杭研的nkv.但是在使用过 ...

  9. [开源]OSharpNS 步步为营系列 - 5. 添加前端Angular模块[完结]

    什么是OSharp OSharpNS全称OSharp Framework with .NetStandard2.0,是一个基于.NetStandard2.0开发的一个.NetCore快速开发框架.这个 ...

  10. java中pojo对象首字母大写导致无法赋值问题

    命名规范(文末附有java命名规范)中指出,属性变量命名应采用驼峰命名的方式,即首字母小写,其他单词首字母大写: 但有时候我们对接三方的接口时,想要封装实体类来接受,但是发现接收到的参数的变量首字母是 ...