关于SetProcessWorkingSetSize减少内存占用 的错误理解

一、C# Winform应用程序占用内存较大解决方法整理(转)
原文:  http://www.jb51.net/article/56682.htm

背景:

微软的 .NET FRAMEWORK 现在可谓如火如荼了。但是,.NET 一直所为人诟病的就是“胃口太大”,狂吃内存,虽然微软声称 GC 的功能和智能化都很高,但是内存的回收问题,一直存在困扰,尤其是 winform 程序,其主要原因是因为.NET程序在启动时,是需要由JIT动态编译并加载的,这个加载会把所有需要的资源都加载进来,很多资源是只有启动时才用的。

以XP 系统为例子,程序启动后,打开任务管理器,会看到占用的内存量比较大,你把程序最小化,会发现该程序占用的内存迅速减小到一个很小的值,再恢复你的程序,你会发现内存占用又上升了,但是比你刚启动时的内存占用值还是小的,这就是一个资源优化的过程,这个过程是操作系统主动完成的。

结论与展望:

创新设计大赛的项目已经快到交付的日期了,都说Winform占用内存大,于是想着看看自己写的基于手机邮件的远程关机软件(Mail_Based_Remote_Shutdown)占用内存情况,整个开发过程自己也在尽量写一些比较优美的代码来减少系统内存占用,今天看了下,刚打开时占用20M内存,然后一点点增加,最后到80多M,真是无法忍受,每次都是写了之后回过头来才发现自己的代码很丑,系统架构师的作用就体现出来了。

这里整理了一些网上关于Winform如何降低系统内存占用的资料,供参考:

1、使用性能测试工具dotTrace 3.0,它能够计算出你程序中那些代码占用内存较多
2、强制垃圾回收
3、多dispose,close
4、用timer,每几秒钟调用:SetProcessWorkingSetSize(Process.GetCurrentProcess().Handle, -1, -1);具体见附录。
5、发布的时候选择Release
6、注意代码编写时少产生垃圾,比如String + String就会产生大量的垃圾,可以用StringBuffer.Append
7、this.Dispose();    this.Dispose(True);   this.Close();    GC.Collect();   
8、注意变量的作用域,具体说某个变量如果只是临时使用就不要定义成成员变量。GC是根据关系网去回收资源的。
9、检测是否存在内存泄漏的情况,详情可参见:内存泄漏百度百科

附录:定期清理执行垃圾回收代码:

    #region 内存回收
    [DllImport("kernel32.dll", EntryPoint = "SetProcessWorkingSetSize")]
    public static extern int SetProcessWorkingSetSize(IntPtr process, int minSize, int maxSize);
    /// <summary>
    /// 释放内存
    /// </summary>
    public static void ClearMemory()
    {
        GC.Collect();
        GC.WaitForPendingFinalizers();
        if (Environment.OSVersion.Platform == PlatformID.Win32NT)
        {
            App.SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1);
        }
    }
    #endregion

二、SetProcessWorkingSetSize函数的骗局
原文地址:http://blog.sina.com.cn/s/blog_49f8960e0100081x.html

我实在不愿意提起这个话题.后来在网上看到几篇文章,深深感觉到,已经有程序员站出来,揭穿这个忽悠了千百万用户的诡计了...
附2篇文章的地址:
http://blog.csdn.net/biku/archive/2006/07/06/886038.aspx
http://blog.csdn.net/zlt982001/archive/2005/08/28/466879.aspx
我这篇文章无非是归纳了几篇文章的内容,并深入的阐明恶意使用该技术带来的坏处.
请一味追求低内存软件的用户们注意了:什么才应该是选择软件的主要因素.

物理内存和虚拟内存

物理内存,在应用中,自然是顾名思义,物理上,真实的插在板子上的内存是多大就是多大了.看机器配置的时候,看的就是这个物理内存.

如果执行的程序很大或很多,就会导致物理内存消耗殆尽.为了解决这个问题,Windows中运用了虚拟内存技术,即拿出一部分硬盘空间来充当内存使用,当内存占用完时,电脑就会自动调用硬盘来充当内存,以缓解内存的紧张.

一个程序,不可避免地要用到虚拟内存,因为不频繁执行或者已经很久没有执行的代码,没有必要留在物理内存中,只会造成浪费;放在虚拟内存中,等执行这部分代码的时候,再调出来.
Windows 的任务管理器可以帮助我们看到进程的虚拟内存.调出任务管理器,点击菜单“查看”-“选择列”,在出现的窗口中,钩上“虚拟内存大小

一个程序到底应该使用多少虚拟内存呢?不一定,但是应该以恰到好处的符合虚拟内存原本作用为最好.
下面将揭穿表面看起来调用了大量图片、大量运行库的程序,为什么才“占用”不到 1 MB 的内存的诡计.

原来是 SetProcessWorkingSetSize 函数

MSDN 对该函数的表述(翻译):使用这个函数来设置应用程序最小和最大的运行空间,只会保留需要的内存.当应用程序被闲置或系统内存太低时,操作系统会自动调用这个机制来设置应用程序的内存.应用程序也可以使用 VirtualLock 来锁住一定范围的内存不被系统释放;当你加大运行空间给应用程序,你能够得到的物理内存取决于系统,这会造成其他应用程序降低性能或系统总体降低性能,这也可能导致请求物理内存的操作失败,例如:建立 进程,线程,内核池,就必须小心的使用该函数.

也就是说,该函数不是节省内存,而是强制把进程的物理内存搬到虚拟内存中.

另外有一些资料上说,该函数“将有可能导致缺页中断,严重影响性能”.
函数原型:
BOOL SetProcessWorkingSetSize(
HANDLE hProcess,
SIZE_T dwMinimumWorkingSetSize,
SIZE_T dwMaximumWorkingSetSize
);
我们用 VB 来做这么一个简单的例子,是程序占用 300 KB 内存吧.

建立一个标准的 VB 工程,在 Form1 中放置一个 Timer1 ,把 Interval 属性设置为 1000 (即 1 秒).然后在代码编辑框中输入以下代码:

Private Declare Function SetProcessWorkingSetSize Lib "kernel32" (ByVal hProcess As Long, ByVal dwMinimumWorkingSetSize As Long, ByVal dwMaximumWorkingSetSize As Long) As Long
Private Declare Function GetCurrentProcess Lib "kernel32" () As Long
Private Sub Timer1_Timer()
SetProcessWorkingSetSize GetCurrentProcess(), 50000, 100000
End Sub
然后生成 工程1.exe,执行,调出任务管理器查看,发现内存占用才 320 KB.如果把定时器关闭,这进程的内存一般 4 MB左右.
必须定时执行该函数,否则虚拟内存会慢慢被调出来,恢复原来的内存大小.
如果要使一个本来需要占用大量内存的程序减低到几百 KB ,使用同样的方法即可.

诡计带来的危害

如果 SetProcessWorkingSetSize 函数被正常使用,是非常有用处的.但是为了蒙骗用户的眼睛,每秒,甚至几十毫秒就把大量内存往虚拟内存里面压,就会带来无可预计的危害.看看这篇文章怎么说:“因为他只是暂时的将应用程序占用的内存移至虚拟内存,一旦,应用程序被激活或者有操作请求时,这些内存又会被重新占用.如果你强制使用该方法来设置程序占用的内存,那么可能在一定程度上反而会降低系统性能,因为系统需要频繁的进行内存和硬盘间的页面交换.”.

没错,如果你使用了这类软件,意味着你的硬盘将每秒将 I/O 大量数据;硬盘的磁针将拼命旋转...(当然硬盘磁针不可能不旋转^_^,只是选择得更厉害而已).

不是说 BT 很伤内存吗?不然,因为现在大多 BT 软件都有缓存技术.且看 Bitcomet 官方对缓存技术的说明:“传统BT高速下载时硬盘会响得很厉害,这是大量的随机读取造成的.... BitComet可以由用户设置缓存大小.... 可以明显地看出牺牲一小部分内存作缓存对硬盘的保护作用.”

是不是有种心寒的感觉?一类软件宁愿牺牲内存,也要减少保护硬盘;而另外一类软件,却为了欺骗用户,让CPU、硬盘更加奔波......

抓一个凶手

这类软件不少,我以其中一个桌面工具为例,揭穿它的假面具(不点名字了).运行该软件后,随意操作一下,然后打开进程管理器,把虚拟内存列调出来,找到该进程,如图3:

OK,20 MB 虚拟内存,而只有 632 KB 物理内存.细心的你会发现,大概每 1 秒,该行都有闪烁的感觉,没错,这正是每秒调用 SetProcessWorkingSetSize 的结果.另外,我们打开 Norton Process Viewer ,查看该进程的 CPU 占用情况,如图4:

可以看到,就算没有操作该软件,但是每秒,都有 3% 的CPU占用起伏(虽然这并不能说明什么).另外,内存框中可以看到物理内存和虚拟内存的占用,两者相去甚远.此外,可以用 Hook API 技术来证明每秒调用 SetProcessWorkingSetSize 的行为.

应该怎么做

这篇文章只想让用户了解软件占用资源的实际.而程序员应该把下功夫,真正从代码中减少内存的消耗,而不是一味忽悠用户.调用 SetProcessWorkingSetSize 会带来某些好处,但是何时调用、如何调用应该符合两个要求:
1,在程序暂时不被使用的时候(例如最小化);
2,物理内存和虚拟内存应处于一个合适的比例(而不是 600 KB 比 20 MB 这么荒唐);
3,或者不调用,让 Windows 去处理.

三、揭发天气秀、桌面秀、雪狐等号称资源占用小的桌面软件的流氓行为!
原文:http://blog.csdn.net/biku/article/details/886038
以下内容需要你对虚拟内存和内存有所了解,但目的只是告诉大家,这些所谓对内存占用小的软件是最为伤硬盘的!

很多人都用过天气秀、雪狐、曰历秀、桌面秀等等桌面软件。这类软件有个最大的特点就是在任务管理器里看,内存占用N小,比记事本都小,只有几百K。很多人就是冲着这点才用这些软件的。

但是,也许大家不知道,这些软件才是占用资源的大户。
这些软件占用资源为什么这么少呢?
Windows编程里有个方法叫做SetProcessWorkingSetSize,对编程有所了解的可以搜索一下。这个方法能够设定程序所占用的内存数(当然有一个最小值)。

比如你打开一个程序,把它最小化,再看任务管理器,里面占用的内存数就是它所使用的最小值,其他暂时用不到的代码就被放到了虚拟内存里。但是,这样做,是影响性能Windows把最多的内存分配给了前台正在运行的程序。

而天气秀等软件所号称的内存压缩技术,就是调用这个SetProcessWorkingSetSize,把内存中的程序代码放到虚拟内存里,调用一次还不够,因为程序运行内存占用不停变化。所以要设定一个Timer(计时器),每隔一段时间就调用一次(通常是几毫秒)。


虚拟内存是指硬盘上的一部分空间。也就是说,当这些软件运行时,每隔几毫秒,你的电脑CPU就要强制把内存中的代码放到硬盘上--往硬盘不停地写。
说实话,这种方式来实现内存占用少(实际上并没有少)很BT。


上面所提到的方法SetProcessWorkingSetSize,是微软提供给程序员的一个方法(或称函数)。
所以在这里,提醒大家:千万不要相信宣传!这些所谓对内存占用小的软件是最占资源最为伤硬盘的! 
--------------------- 
作者:sinat_15155817 
来源:CSDN 
原文:https://blog.csdn.net/sinat_15155817/article/details/78556603 
版权声明:本文为博主原创文章,转载请附上博文链接!

猜你喜欢

转载自blog.csdn.net/yyws2039725/article/details/85480263
今日推荐