SetProcessWorkingSetSize 降低程序运行内存
在项目中对程序性能优化时,发现用SetProcessWorkingSetSize() 方法使内存降低了很多,于是查阅了相关的资料如下。
一 SetProcessWorkingSetSize 的工作原理
以下来自:http://blog.csdn.net/zlt982001/archive/2005/08/28/466879.aspx
那么我的程序为什么能够将占用的内存移至虚拟内存呢?
其实,你也可以,试试看把一个程序最小化到任务栏,再看看任务管理器,看到没,你的程序占用的实际内存一下子减少了,看来并不是我有什么方法能够压缩内存,而是操作系统本身就有这个机制,即当程序不使用时(最小化),操作系统会调用某些命令,来将该程序占用的内存移至虚拟内存,只保留一小部分常规代码
所以我们就看到了 这种情景,占用的内存一下子就缩小了。
那么:系统到底调用了什么指令呢?能不能在不缩小窗体的情况下来释放内存呢?
看看这个API SetProcessWorkingSetSize
这是从MSDN摘下的原话
Using the SetProcessWorkingSetSize function to set an application's minimum and maximum working set sizes does not guarantee that the requested memory will be reserved, or that it will remain resident at all times. When the application is idle, or a low-memory situation causes a demand for memory, the operating system can reduce the application's working set. An application can use the VirtualLock function to lock ranges of the application's virtual address space in memory; however, that can potentially degrade the performance of the system.
使用这个函数来设置应用程序最小和最大的运行空间,只会保留需要的内存。当应用程序被闲置或系统内存太低时,操作系统会自动调用这个机制来设置应用程序的内存。应用程序也可以使用 VirtualLock 来锁住一定范围的内存不被系统释放。
When you increase the working set size of an application, you are taking away physical memory from the rest of the system. This can degrade the performance of other applications and the system as a whole. It can also lead to failures of operations that require physical memory to be present; for example, creating processes, threads, and kernel pool. Thus, you must use the SetProcessWorkingSetSize function carefully. You must always consider the performance of the whole system when you are designing an application.
当你加大运行空间给应用程序,你能够得到的物理内存取决于系统,这会造成其他应用程序降低性能或系统总体降低性能,这也可能导致请求物理内存的操作失败,例如:建立 进程,线程,内核池,就必须小心的使用该函数。
========================
事实上,使用该函数并不能提高什么性能,也不会真的节省内存。
因为他只是暂时的将应用程序占用的内存移至虚拟内存,一旦,应用程序被激活或者有操作请求时,这些内存又会被重新占用。如果你强制使用该方法来 设置程序占用的内存,那么可能在一定程度上反而会降低系统性能,因为系统需要频繁的进行内存和硬盘间的页面交换。
BOOL SetProcessWorkingSetSize(
HANDLE hProcess,
SIZE_T dwMinimumWorkingSetSize,
SIZE_T dwMaximumWorkingSetSize
);
将 2个 SIZE_T 参数设置为 -1 ,即可以使进程使用的内存交换到虚拟内存,只保留一小部分代码
而桌面日历秀 之所以能够 总是保持 最小内存,是因为使用了定时器,不停的进行该操作,,所以性能可想而知,虽然换来了小内存的假象,对系统来说确实灾难。
当然,该函数也并非无一是处,
1 。当我们的应用程序刚刚加载完成时,可以使用该操作一次,来将加载过程不需要的代码放到虚拟内存,这样,程序加载完毕后,保持较大的可用内存。VB尤甚
2.程序运行到一定时间后或程序将要被闲置时,可以使用该命令来交换占用的内存到虚拟内存。
最后,附上VB 调用的API 代码
Option Explicit
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
SetProcessWorkingSetSize GetCurrentProcess, -1, -1
将当前进程使用的内存归0,请放在适当的地方
二 区分物理内存、虚拟内存、Working Set(Memory)、Memory
以下来自:http://blog.joycode.com/qqchen/archive/2004/03/17/16434.aspx
这个问题在CSDN上碰到好几次,我每次都只给出了简单的答案:不要参考Task Manager的Mem Usage数据,那个数据的大小对程序性能没有直接影响。
下面是我分析这问题的一些思路,希望对对这个问题感兴趣的朋友有所帮助
Q: Is .NET Alone?
A: Nope! 前面Saucer说过了,这不是.NET的问题,所有Windows程序都有类似的行为。例如下面的C程序:
void main { while(1); } //死循环,便于我们察看Task Manager
初次运行在我的机器上Mem Usage是632K,把Console最小化以后再恢复,Mem Usage变成了36K。显然,这不是一个.NET独有的问题,而是Windows Memory Management的问题。那么和.NET的GC机制也不会有太大的关系——虽然问题的表现形式很容易让人联想到GC。
Q: How much memory does my program use?
A: 回答这个问题并不容易。先来看看操作系统虚拟内存管理的一些基本概念:每个Windows进程都拥有4G的地址空间,但是你的机器显然没有4G的物理内存。在多任务环境下,所有进程使用的内存总和可以超过计算机的物理内存。在特定的情况下,进程的一部分可能会从物理内存中删除而被暂存在硬盘的文件里(pagefile),当进程试图访问这些被交换到pagefile里的内存的时候,系统会产生一个缺页中断(page fault),这时候Windows内存管理器会负责把对应的内存页重新从硬盘调入物理内存。
在某个时间内,一个进程可以直接访问到的物理内存(不发生缺页中断)叫做这个进程的Working Set;而一个进程从4G的地址空间当中实际分配(commit)了的、可访问的内存称为Committed Virtual Memory。Committed VM可能存在于Page File当中,WorkingSet则一定位于物理内存。
所以要回答上面的问题先要反问一句:What're you talking about? Physical Memory or Committed Memory?
Q: What is this "Mem Usage" data?
A: From Task Manager Help: In Task Manager, the current Working Set of a process, in kilobytes.
Mem Usage这个名字多少有些误导。它只表示这个进程当前占用的物理内存,也就是WorkingSet。WorkingSet不表示进程当前“占用”的所有虚拟内存,该进程可能还有一部分数据被交换到pagefile当中。这些数据只有在被访问的时候才会被加载到物理内存。
Task Manager有另一列数据:VM Size,表示了一个进程分配的虚存(Committed Visual Memory)——实际的定义要比这个复杂一些,但这个定义对我们目前分析的问题已经足够了。以前面的C程序为例,在最小化前后的VM Size都是176K,并没有变化。
所以,结论很简单:当一个Windows程序被最小化的时候,Windows内存管理器把该进程的WorkingSet减到最小(根据先进先出FIFO或者最近最少使用LRU),把大部分数据交换到pagefile里。这很容易理解:我们通常总是希望为前台的应用程序留出更多物理内存,从而具有更好的性能。当该程序从最小化恢复的时候,Windows也不会完全加载程序的所有虚存,只是加载了必要的部分。这也很容易理解:程序启动阶段的代码通常在启动之后很少访问(对.NET程序尤其如此,向fusion这样的模块在程序正常加载之后如果没有用到Reflection通常用不到)。
Q: So, Do we want a smaller workingset, or a larger one?
A: It depends. Conventional Wisdom tells us: The smaller, the better. 但是在虚存的问题上却没这么简单。如果WorkingSet太小,程序运行过程中会产生很多缺页中断,这会严重影响程序的性能。另一方面,WorkingSet太大会浪费“宝贵的”物理内存,降低整个系统的性能。 通常情况下(除非是对性能非常敏感的应用程序,并且你对Windows的内存管理了如指掌),建议不要在程序中自己调整WorkingSet的大小,而把这个任务交给Windows内存管理器。调整的方法Saucer有提到: SetProcessWorkingSetSize();
Q: Final Question, Does my program really occupy that much physical memory?
A: 这个问题看上去土了点——那个数字明明白白的写在Task Manager里面。
sam1111用vadump检查的结果显示进程WorkingSet减小的主要原因是很多DLL在从最小化恢复的时候没有被加载到物理内存。我们知道DLL的一个特点是代码共享,以NTDLL.DLL为例,整个Windows系统的几乎所有应用程序(具体地说,Win32子系统的所有程序)都需要引用NTDLL.DLL,如果每人一份,光这个文件就的占用几十兆内存。Windows地解决办法是只在物理内存中保存一份NTDLL.DLL的COPY,所有引用这个DLL的程序都把这一份COPY映射到自己的内存空间里面,共享NTDLL.DLL的代码段(每个进程的数据段仍然是独立的)。所以虽然NTDLL.DLL的大小被计算在你的程序的WorkingSet里面,但是从你的程序中去掉对这个DLL的引用并不会真的释放多少物理内存——你不用,别人还在用呢!
所以,你的程序“独占”的物理内存远没有Mem Usage所表示的那么多,需要从Mem Usage里面扣除很多Shared Code Page (vadump里面可以看到)。
结论?不要参考Task Manager的Mem Usage数据,那个数据的大小对程序性能没有直接影响。用Perfomence Monitor里面与.NET相关的Counter要容易、准确的多。
SetProcessWorkingSetSize 降低程序运行内存的更多相关文章
- Java程序运行内存机制
Java程序运行内存机制 栈内存包留调用方法.变量的区域,堆内存是new对象的区域,方法区为保存class文件的区域. 程序刚开始时,先加载类文件相应的数据到方法区,然后就从main()方法开始执行. ...
- 关于程序猿怎样降低程序Bug的若干建议
毫无疑问,程序猿是善于思考问题的一族. 一个程序的编写都是通过:思考.设计.编写.调试.測试以及执行这些主要的阶段. 但大部分程序猿都有一个问题就是不太愿意測试自己的代码. 他们草草的调式完毕以后就觉 ...
- 【转载】EmptyWorkingSet 程序运行内存整清理
网络上找了很多关于内存整理的文章,不外乎都是使用EmptyWorkingSet来实现.就如下面这段代码. #include "stdafx.h"#include <windo ...
- Java 程序优化 (读书笔记)
--From : JAVA程序性能优化 (葛一鸣,清华大学出版社,2012/10第一版) 1. java性能调优概述 1.1 性能概述 程序性能: 执行速度,内存分配,启动时间, 负载承受能力. 性能 ...
- java程序性能优化
一.避免在循环条件中使用复杂表达式 在不做编译优化的情况下,在循环中,循环条件会被反复计算,如果不使用复杂表达式,而使循环条件值不变的话,程序将会运行的更快. 例子: import java.util ...
- 黑马程序员-懒加载 lazy loading
懒加载:延迟加载,当程序启动时不加载资源,当程序需要这些资源时再去加载.需要的时候再加载的一种方式,能够减少内存的占用,效率高.其本质是重写get方法. 背景:由于ios内存有限,如果我们一次性将所有 ...
- 编写出色的GNU/Linux程序
http://advancedlinuxprogramming.com提供了本书电子版的免费下载. 1 与执行环境交互 关于参数 C语言程序的main()函数使用两个参数和执行环境交互--(int)a ...
- 《疯狂Java:突破程序员基本功的16课》读书笔记-第二章 对象与内存控制
Java内存管理分为两个方面:内存分配和内存回收.这里的内存分配特指创建Java对象时JVM为该对象在堆内存中所分配的内存空间.内存回收指的是当该Java对象失去引用,变成垃圾时,JVM的垃圾回收机制 ...
- [JAVA] java程序性能优化
一.避免在循环条件中使用复杂表达式 在不做编译优化的情况下,在循环中,循环条件会被反复计算,如果不使用复杂表达式,而使循环条件值不变的话,程序将会运行的更快. 例子: import java.util ...
随机推荐
- Redis记录-Redis介绍
Redis是一个开源,高级的键值存储和一个适用的解决方案,用于构建高性能,可扩展的Web应用程序. Redis有三个主要特点,使它优越于其它键值数据存储系统 - Redis将其数据库完全保存在内存中, ...
- SQL语句(七)简单查询
--简单信息查询 --例1 查询所有学生的信息 --学生 -- Student --所有学生 -- 不限定班级.性别.年龄等条件 --所有信息 -- 所有字段,* select * from stud ...
- R8:Learning paths for Data Science[continuous updating…]
Comprehensive learning path – Data Science in Python Journey from a Python noob to a Kaggler on Pyth ...
- mount过程分析之六——挂载关系(图解)【转】
转自:https://blog.csdn.net/zr_lang/article/details/40343899 引言 写到这里我们已经从mount文件系统调用的入口开始,分析到内核的mount,通 ...
- mysql5.7 主从复制的正常切换【转】
目前环境如下: master server IP:172.17.61.131 slave server IP:172.17.61.132 mysql version: mysql-5.7.21-lin ...
- Linux dd命令中dsync与fdatasync的区别【转】
在Linux系统中经常会使用dd命令来测试硬盘的写入速度,命令会涉及到两个参数:dsync与fdatasync,本文介绍一下其区别. dd if=/dev/zero of=/tmp/1Gbytes b ...
- 使用管道和cronolog切割日志
安装cronolog git clone https://github.com/fordmason/cronolog ./configure make && make install ...
- 解决UnicodeDecodeError: 'ascii' codec can't decode byte 0xcf in position 7: ordinal not in range(128)
在Windows下同时装了Python2和Python3,但是在使用命令给pip更新的时候,出现了以下错误: 解决办法:修改mimetypes.py文件,路径位于python的安装路径下的Lib\mi ...
- Vue 实现一个中国地图
参考:https://www.cnblogs.com/mazey/p/7965698.html 重点:如何引入中国地图js文件,china.js require('echarts/map/js/chi ...
- Java实现继承过程概述
super(); 在调用子类的构造器的时候,如果没有显示的写出 super(); ,那么,编译器会在佛那个加上 super(); 无参构造器 如果想调用父类的有参构造器,那么,必须显示的调用,编译器不 ...