windows用戶對象或者GDI對象個數限制整理

寫這篇文章源自查看一個dump,CEF在創建位圖數據的時候崩潰了。

我很納悶爲什麼會失敗,我首先想到的是程序是不是有資源泄露,導致GDI句柄數過高導致。

把堆棧打印出來發現GDI資源個數0x564個,User對象個數0x5e5個,都才一千多個,應該不多吧。截圖如下:

 

所以又查詢了下window對GDI和USER對象的個數限制。

msdn介紹GDI對象: https://docs.microsoft.com/zh-cn/windows/win32/sysinfo/gdi-objects

對個數的限制:

There is a theoretical limit of 65,536 GDI handles per session. However, the maximum number of GDI handles that can be opened per session is usually lower, since it is affected by available memory.

Windows 2000: There is a limit of 16,384 GDI handles per session.

There is also a default per-process limit of GDI handles. To change this limit, set the following registry value:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\GDIProcessHandleQuota

This value can be set to a number between 256 and 65,536.

Windows 2000: This value can be set to a number between 256 and 16,384.

系統對每個session的限制是65536(64KB),對每個進程的限制可以通過註冊表來修改,範圍是256-65536

windows 2000的比較小,做了特殊說明。

特別主要的是專門提到了,會受可用內存的影響。

However, the maximum number of GDI handles that can be opened per session is usually lower, since it is affected by available memory.

 

msdn介紹USER對象: https://docs.microsoft.com/zh-cn/windows/win32/sysinfo/user-objects

對個數的限制:

There is a theoretical limit of 65,536 user handles per session. However, the maximum number of user handles that can be opened per session is usually lower, since it is affected by available memory. There is also a default per-process limit of user handles. To change this limit, set the following registry value:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\USERProcessHandleQuota

This value can be set to a number between 200 and 18,000.

系統對每個session的限制是65536(64KB),對每個進程的限制可以通過註冊表來修改,範圍是200 -18000

同樣也說明了會受到可用內存的影響!

 

那麼dump中查看到當時進程使用的GDI和USER對象個數都是1000多,會不會超過了限制了,需要看下這兩個註冊表值:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\GDIProcessHandleQuota

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\USERProcessHandleQuota

在我win7和win10電腦上默認值都是10000,所以是遠遠沒有超過限制的。

 

最後,那就很可能是內存不足的原因了吧,然後看了下內存使用情況,果然佔用比非常高,可用物理內存也比較小。最終導致創建GDI資源失敗了。

 

相關API:

GetGuiResources 獲取GDI或者USER對象的個數

https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getguiresources


    DWORD dwCount = 0;

    dwCount = ::GetGuiResources(GetCurrentProcess(), GR_GDIOBJECTS); // 獲取當前進程GDI對象個數

    dwCount = ::GetGuiResources(GR_GLOBAL, GR_GDIOBJECTS); // 獲取所有進程對象個數


    dwCount = ::GetGuiResources(GetCurrentProcess(), GR_USEROBJECTS); // 獲取當前進程USER對象個數

    dwCount = ::GetGuiResources(GR_GLOBAL, GR_USEROBJECTS); // 獲取所有進程USER對象個數

函數第二個參數可以使用另外兩個參數:GR_GDIOBJECTS_PEAK,GR_USEROBJECTS_PEAK
不過是需要windows 7 或者 Windows Server 2008 R2以及以上版本才行。

Return the peak count of GDI objects.

Windows Server 2008, Windows Vista, Windows Server 2003 and Windows XP:  This value is not supported until Windows 7 and Windows Server 2008 R2.

 

參考資料:

https://www.xuebuyuan.com/1029053.html

 

 

無關的話題:

msdn中GDI對象以及USER對象放在同一個目錄講解的還包括內核對象:

https://docs.microsoft.com/zh-cn/windows/win32/sysinfo/kernel-objects

文章中的幾個圖對於理解內核對象的生命週期以及跨進程使用很有幫助。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章