Windows NT 中,系统资源如GDI资源是如何管理的?

lujun-cc 2006-04-20 05:55:51
在Windows中,使用GDI资源,使用完毕之后都要释放,那么,要是不释放的话,会出现啥子问题?

我对一个使用GDI资源但使用完毕后不释放资源的程序进行观察,通过不停的刷新界面,任务管理器中该进程的GDI对象数不断增加,当达到9999时,该进程的界面绘制就不正常了,因此,想问问Windows NT中一共有多少的GDI资源可供使用,或者说Windows NT中对GDi资源是如何管理的?


乞求大哥们出来讲讲课!
...全文
627 点赞 收藏 21
写回复
21 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
OOPhaisky 2006-07-25
恩,学习了!
回复
lujun-cc 2006-06-19
Can you tell me the name of your book?
回复
FengYuanMSFT 2006-05-27
There is still one more important limitation you've not considered. That is kernel mode paged pool.

Most of memory allocated for GDI objects are allocated from kernel mode, from kernel mode paged pool to be exact. There is a system-wide limitation of around 200 Mb for kernel mode paged pool, and 48 Mb per process.

Most of GDI objects are quite small, so this is not a problem. But there are two types of GDI objects which can be very large. They are DDB and GDI region.

Read my book to know more about GDI objects.
回复
ztony007 2006-05-24
厉害.
回复
pomelowu 2006-04-29
帅!
回复
逸学堂 2006-04-29
如果lz不同意,我将马上删除。
http://www.exuetang.net/article/NewsViewAdmin.aspx?NewsId=209

连接如上。
回复
逸学堂 2006-04-29
不错,支持原创。

收藏,http://www.exuetang.net
回复
lujun-cc 2006-04-29
GDI资源为什么会耗尽呢,到哪种程度才表现为耗尽呢?
为了回答这一问题,我们用Windows自带的任务管理器观察后发现,当程序界面开始混乱时,进程的GDI对象值为9999,那么为什么GDI对象达到9999后界面才发生混乱呢,带着这个疑问,我查找了一些资料,简单的了解到了Windows对GDI对象的管理方式。
GDI对象,实际上是Windows系统维护的一些数据结构。微软基于稳定性和健壮性考虑,将所有GDI对象的管理权都交给Windows系统的对象管理器管理,用户只能通过系统返回的“句柄”来操作这些对象。
在Windows 2000中,句柄实际上是一个DWORD类型的值。该DWORD值是一个32比特位的数据,它又分为两个部分:Table Index及Uniqueness Identifier,他们各占16位,因此,在理论上来说,Windows中的每个进程,所能访问的GDI对象的最大值是64K。然而,在Windows 2000中,客户句柄的最大数目被硬设置为16384 (16K);
然而,在Windows 2000中,既便客户句柄的最大数目被硬设置为16384,那么为什么在实际中GDI对象增加到9999后,程序界面就开始混乱了呢?原来,在Windows2000中,每进程的GDI对象的最大值又被默认为10000——据微软资料显示,之所以设置为10000,是为了阻止“Bad”程序分配过多的资源,因此,当GDI对象达到9999之后,程序就不能再创建新的GDI资源,这样,每次都使用新建资源来绘制界面的程序就产生混乱了。
不过,在Windows 2000及以后的操作系统中,每个进程可以创建的GDI对象的最大值,是可以通过修改注册表来重新设置的,在Windows 2000中,该注册表项所为:HKEY_LOCAL_MACHINE\ SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows下的"GDIProcessHandleQuota"。设置完新的值后,重启计算机后,系统中每进程可以使用的GDI对象数就会变成你新设置的数。
然而,上述说法并不完全正确!
据SYBASE的一份资料显示(http://www.sybase.com/detail?id=1019174),在Windwos2000中,只可以对”GDIProcessHandleQuota”值进行微调,如果设置的值超过15000,系统就变得不稳定。事实上,我在Windows 2000中进行了测试,当GetGuiResources函数的返回值为12288(12K)时,就已经不能创建新的GDI对象了,也就是说,在Windows 2000中当一个进程总的GDI对象数达到12288以后,就不能再创建新的GDI对象了。
那么,在Windows 2000中,进程所能创建的GDI对象数,是每个进程独立的,还是要受限于Windows操作系统呢?为此,我写了一个check程序,该程序批量创建指定数目的BRUSH对象,并统计本进程的GDI对象数及系统中总的GDI对象数,其运行界面如下(这里图显示不出来,不过无关紧要)

其中统计系统中总的GDI对象的代码如下:
int GetGDINumInSystem(void)
{
int nGDINums = 0; /*所有进程的GDI对象之和*/
int nProcess = 0; /*系统中的进程数*/

DWORD aProID[1024];
DWORD cbNeeded;
::EnumProcesses ( aProID, sizeof(aProID), &cbNeeded );

/*系统中进程总数*/
nProcess = cbNeeded / sizeof ( DWORD );

/*统计每个进程的GDI对象数*/
for ( INT i=0; i < nProcess; i ++ )
{
HANDLE hPro = ::OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, aProID[i] );

nGDINums += ::GetGuiResources ( hPro, GR_GDIOBJECTS );

CloseHandle ( hPro );
}

return nGDINums;
}

使用此check程序,做如下试验:
① 修改Windows 2000的注册表项” GDIProcessHandleQuota”值为12000;
② 开启一个check进程,在其中创建11000个GDI对象!
③ 开启第二个check进程(第一个进程不关闭),在其中创建11000个GDI对象。
试验结果表明,第一个进程的对象可以顺利创建,而第二个进程的对象则不能顺利创建,这就说明,在Windows 2000中,每个进程可以创建的GDI对象数,不仅在进程内部有一定限制,而且还受限于整个操作系统。经多次试验表明,当Windows 2000系统中总的GDI对象数达到15900以后的某个值后,进程就不能再创建GDI对象了,系统就变得不稳定了,至于该临界值到底是多少,各次试验结果并不一致,但是都在15900以后。



上面的测试是在Windows 2000中进行的,那么,在Windows 2003中,情况又是什么样呢?立即动手,到2003系统中,修改注册表项”GDIProcessHandleQuota”为20000,然后运行测试程序并在其中创建20000个GDI对象,一切正常! 再改,30000,运行,仍然正常;……直到改到了70000的时候,系统运行才会出现界面绘制问题,在这样的事实下,不得不做假设:难道Windows 2003中取消了客户GDI句柄最多16K的限制,而将限制设到了64K?
为了验证这个推测,我使用check程序直接创建64K的GDI资源,运行结果表明,当进程创建了一定的GDI对象之后,就不能创建新的GDI对象了,这表明上面的推测不完全正确,不过,基于在Windows 2000中的试验经验,很快就想到了在Windows 2003中系统可以创建的GDI对象应该还要受限于操作系统,也就是说:Windows 2003中放宽了每个进程可以创建的GDI对象数目,但是整个系统中GDI对象数不能超过某个值。为验证此结果,做如下试验:
① 修改Windows 2003的注册表项” GDIProcessHandleQuota”值为50000;
② 开启一个check进程,在其中创建40000个GDI对象!
③ 开启第二个check进程(第一个进程不关闭),在其中创建40000个GDI对象。
试验结果基本上和Windows 2000中的结果类似,唯一不同的是,在第二个进程创建GDI对象的过程中,当系统中总GDI对象达到63700以后的某个值后才会创建失败。同样,该临界值也不固定,不过多次试验表明,当总的GDI对象数达到63700以后,系统就变得不稳定了。


结论
经过上面的分析,我们可以知道,在Windows 2000/2003 操作系统中,每个进程可以创建的GDI对象,受限于三个方面因素:系统本身的两个方面的限制和Windows注册表中设置的最大值限制。
首先,每个进程可以创建的GDI对象数,在理论上为64K,但是在Windows 2000中,系统将客户可以创建的GDI句柄数硬设置为不能超过16K,而事实上当GDI对象数达到12K之后,系统即不正常;在Windows 2003中,系统放宽了对GDI对象数的限制,使得每个进程可以使用的GDI对象数接近64K;

其次,每个进程可以创建的GDI对象数,还受限于操作系统中GDI对象总数;在Windows 2000中,当系统中总的GDI对象达到15900以后的某个值后,进程就不能再创建新的GDI对象了;在20003中,这个值增加到63700以后的某个值。但是,到底是哪个值,则不固定。

最后,进程可创建的最大GDI对象数目还受限于注册表中HKEY_LOCAL_MACHINE\ SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows下的"GDIProcessHandleQuota" 项所设置的值,该值设置了Windows中每个进程可以创建的最大GDI对象数,在Windows 2000及2003系统中,其默认均为10000,这也就说明了当程序创建的GDI对象数达到9999之后界面为什么会混乱。
回复
lujun-cc 2006-04-29
经过几天的查找,没有发现比较系统的介绍windows 2000/2003中GDI资源管理方式的资料,只有一些零散的信息,加上自己的一些试验,我整理了一篇东西,上面发的是结论部分,应老迈同志要求,就把另外一部分也一起贴出来,欢迎大家讨论!
回复
Promedini 2006-04-29
修改注册表解决
回复
lujun-cc 2006-04-28
欢迎指正
回复
lujun-cc 2006-04-28
经过上面的分析,我们可以知道,在Windows 2000/2003 操作系统中,每个进程可以创建的GDI对象,受限于三个方面因素:系统本身的两个方面的限制和Windows注册表中设置的最大值限制。

首先,每个进程可以创建的GDI对象数,在理论上为64K,但是在Windows 2000中,系统将客户可以创建的GDI句柄数硬设置为不能超过16K,而事实上当GDI对象数达到12K之后,系统即不正常;在Windows 2003中,系统放宽了对GDI对象数的限制,使得每个进程可以使用的GDI对象数接近64K;

其次,每个进程可以创建的GDI对象数,还受限于操作系统中GDI对象总数;在Windows2000中,当系统中总的GDI对象达到15900以后的某个值后,进程就不能再创建新的GDI对象了;在20003中,这个值增加到63700以后的某个值。但是,到底是哪个值,则不固定。

最后,进程可创建的最大GDI对象数目还受限于注册表中HKEY_LOCAL_MACHINE\ SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows下的"GDIProcessHandleQuota" 项所设置的值,该值设置了Windows中每个进程可以创建的最大GDI对象数,在Windows 2000及2003系统中,其默认均为10000,这也就说明了当程序创建的GDI对象数达到9999之后界面为什么会混乱。
回复
lujun-cc 2006-04-21
感谢pomelowu(羽战士) ( ) 给的这个链接,正是我要的,正在看,要是可能的话,翻译出来后再贴上来!
回复
pomelowu 2006-04-20
要是不释放的话,会出现啥子问题?
NT架构下,进程的界面会花。9x架构下,系统会崩溃
回复
pomelowu 2006-04-20
Windows NT has a per-process quotas for GDI and User resources. They
are set as 16k GDI and 64k User objects.
回复
pomelowu 2006-04-20
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dngenlib/html/msdn_handles1.asp
回复
chenhu_doc 2006-04-20
henan_lujun (地平风线)

不好意思 班门弄斧了
回复
chenhu_doc 2006-04-20
国内的资源用 baidu
国外用 google
肯定有满意的答案
回复
发帖
其它技术问题
创建于2007-09-28

3842

社区成员

C/C++ 其它技术问题
申请成为版主
帖子事件
创建了帖子
2006-04-20 05:55
社区公告
暂无公告