国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

如何洞察 C# 程序的 GDI 句柄泄露

這篇具有很好參考價值的文章主要介紹了如何洞察 C# 程序的 GDI 句柄泄露。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

一:背景

1. 講故事

前段時間有位朋友找到我,說他的程序界面操作起來很慢并且卡頓等一些不正?,F(xiàn)象,從任務(wù)管理器看了下 GDI句柄 已經(jīng)到 1w 了,一時也找不出什么代碼中哪里有問題,讓我?guī)兔聪拢鋵嵾@種問題看內(nèi)存dump作用不是很大,主要是寫腳本很麻煩,這一篇我們就來簡單聊聊如何洞察此類問題。

二:如何洞察泄露

1. 一個測試小案例

在 windows 上gdi的句柄類型有很多,比如:pen,font,bitmapdevice 等,具體可以網(wǎng)上搜一下,這里我就造一個 bitmap 的句柄泄露,參考代碼如下:


        private void button1_Click(object sender, EventArgs e)
        {
            Task.Factory.StartNew(() =>
            {
                Bitmap bmp = new Bitmap(100, 100);

                for (int i = 0; i < 10000; i++)
                {
                    bmp.GetHbitmap();
                    Thread.Sleep(100);
                }
            });
        }

代碼非常簡單,大概 100ms 泄露一個 bitmap 句柄,接下來把程序跑起來點擊 Button_Click 按鈕,然后上瑞士軍刀 WinDbg 附加進(jìn)程。

2. 如何觀察GDI泄露

觀察 GDI句柄 是否異常,最簡單的方法就是看任務(wù)管理器中的 GDI對象 一列,截圖如下:

如何洞察 C# 程序的 GDI 句柄泄露

但這里有一個問題,你只知道有一個總數(shù),并不知道是哪種句柄類型的泄露,比如是:bitmap? font ?device? 對吧。

那怎么辦呢?這就需要考驗一點基礎(chǔ)知識了,你要知道 GDI 的句柄表(GDI Shared Handle Table)是維護在用戶態(tài)的虛擬地址上,區(qū)別于維護在內(nèi)核中的 ObjectTable,可以用 !address 驗證下。

0:011> !address 

        BaseAddress      EndAddress+1        RegionSize     Type       State                 Protect             Usage
--------------------------------------------------------------------------------------------------------------------------
+      294`d1500000      294`d1681000        0`00181000 MEM_MAPPED  MEM_COMMIT  PAGE_READONLY                      Other      [GDI Shared Handle Table]

0:011> !address 294`d1500000

Usage:                  Other
Base Address:           00000294`d1500000
End Address:            00000294`d1681000
Region Size:            00000000`00181000 (   1.504 MB)
State:                  00001000          MEM_COMMIT
Protect:                00000002          PAGE_READONLY
Type:                   00040000          MEM_MAPPED
Allocation Base:        00000294`d1500000
Allocation Protect:     00000002          PAGE_READONLY
Additional info:        GDI Shared Handle Table


Content source: 1 (target), length: 181000

在這 1.5M虛擬地址段中就雪藏了我們要找的各句柄的統(tǒng)計信息,但要挖它需要寫腳本,再配合 GDICELL 結(jié)構(gòu)體,分組其中的 wType 句柄類型。


typedef struct {
  PVOID64 pKernelAddress; // 0x00
  USHORT wProcessId;      // 0x08
  USHORT wCount;          // 0x0a
  USHORT wUpper;          // 0x0c
  USHORT wType;           // 0x0e
  PVOID64 pUserAddress;   // 0x10
} GDICell;                // sizeof = 0x18

雖然可以手工分組出來,但這種問題你肯定不是第一個遇到,早有人寫了一個工具來解決這類問題,它就是 GDIView.exe,大家可以網(wǎng)上搜一下。

打開 GDIView 之后,可以很清楚的看到 WindowsFormsApp1 程序中各個句柄的統(tǒng)計信息,并且 type=Bitmap 是非常可疑的,截圖如下:

如何洞察 C# 程序的 GDI 句柄泄露

知道了是 Bitmap 的句柄泄露,定位的范圍一下子就小了很多,長舒一口氣。

3. 如何尋找 Bitmap 的底層函數(shù)

熟悉 Windows 的朋友應(yīng)該都知道 GDI 的邏輯是封裝在底層的 GDI32.dll 中,模塊信息如下:


0:012> lmvm gdi32
Browse full module list
start             end                 module name
00007ff9`b0c80000 00007ff9`b0cab000   GDI32      (deferred)             
    Image path: C:\windows\System32\GDI32.dll
    Image name: GDI32.dll
    Browse all global symbols  functions  data
    Image was built with /Brepro flag.
    Timestamp:        3EE1D71F (This is a reproducible build file hash, not a timestamp)
    CheckSum:         0002B228
    ImageSize:        0002B000
    File version:     10.0.19041.2130
    Product version:  10.0.19041.2130
    File flags:       0 (Mask 3F)
    File OS:          40004 NT Win32
    File type:        2.0 Dll
    File date:        00000000.00000000
    Translations:     0409.04b0
    Information from resource tables:
        CompanyName:      Microsoft Corporation
        ProductName:      Microsoft? Windows? Operating System
        InternalName:     gdi32
        OriginalFilename: gdi32
        ProductVersion:   10.0.19041.2130
        FileVersion:      10.0.19041.2130 (WinBuild.160101.0800)
        FileDescription:  GDI Client DLL
        LegalCopyright:   ? Microsoft Corporation. All rights reserved.

言外之意就是可以在 GDI32 模塊中下方法斷點,這時候問題就來了,到底擱哪個方法下呢?這個只能求助 MSDN 了,功夫不負(fù)有心人,找到了一篇很老的文章:https://learn.microsoft.com/en-us/archive/msdn-magazine/2003/january/detect-and-plug-gdi-leaks-with-two-powerful-tools-for-windows-xp

如何洞察 C# 程序的 GDI 句柄泄露

從圖中看記載的非常詳細(xì),但我親自觀察下來有些方法找不到,所以只能做個參考吧,不過在 Windbg 中提供了一個非常好的 bm 命令,它可以對方法名進(jìn)行 模糊斷點,比如 bm gdi32!*Bitmap* 就可以一口氣下 45 個斷點。


0:012> bm gdi32!*Bitmap* "? @$tid; k; gc"
  0: 00007ff9`b0c86f7c @!"GDI32!IsCreateBitmapPresent"
  1: 00007ff9`b0c87216 @!"GDI32!_imp_load_CreateDIBitmap"
  2: 00007ff9`b0c8906c @!"GDI32!_imp_load_DwmCreatedBitmapRemotingOutput"
  3: 00007ff9`b0c86460 @!"GDI32!NtGdiGetBitmapDpiScaleValue"
  4: 00007ff9`b0c8850c @!"GDI32!_imp_load_ClearBitmapAttributes"
  5: 00007ff9`b0c88745 @!"GDI32!_imp_load_CreateDiscardableBitmap"
  6: 00007ff9`b0c84470 @!"GDI32!CreateBitmapStub"
 ...
 42: 00007ff9`b0c8713e @!"GDI32!_imp_load_GetBitmapBits"
 43: 00007ff9`b0c89580 @!"GDI32!GdiConvertBitmapV5"
 44: 00007ff9`b0c89080 @!"GDI32!DwmCreatedBitmapRemotingOutput"
 45: 00007ff9`b0c8aaac @!"GDI32!_imp_load_SetBitmapDimensionEx"

0:007> .bpcmds
bu0 @!"GDI32!IsCreateCompatibleBitmapPresent" "? @$tid; k; gc";
bu1 @!"GDI32!_imp_load_CreateDIBitmap" "? @$tid; k; gc";
bu2 @!"GDI32!_imp_load_DwmCreatedBitmapRemotingOutput" "? @$tid; k; gc";
bu3 @!"GDI32!NtGdiGetBitmapDpiScaleValue" "? @$tid; k; gc";
bu4 @!"GDI32!_imp_load_ClearBitmapAttributes" "? @$tid; k; gc";
bu5 @!"GDI32!_imp_load_CreateDiscardableBitmap" "? @$tid; k; gc";
...

天網(wǎng)恢恢,疏而不漏,肯定會命中其中一個的,接下來繼續(xù) g 讓程序跑起來,你會看到有大量的方法被命中,并且仔細(xì)觀察會有一個用戶態(tài)函數(shù) <button1_Click>b__1_0,截圖如下:

如何洞察 C# 程序的 GDI 句柄泄露

此時這個托管函數(shù)就是重點懷疑對象,也就很輕松的找到問題之所在,有些朋友可能要問,這樣重復(fù)的信息是不是會很多,那當(dāng)然了,大家可以根據(jù)輸出信息做下一步的洞察,比如上面的 gdiplus!CopyOnWriteBitmap::CreateHBITMAP 函數(shù)會特別多,這時候可以重新 bp 來縮小范圍,對吧!參考代碼如下:


0:010> bc *
0:010> bp gdiplus!CopyOnWriteBitmap::CreateHBITMAP "? @$tid; k; gc"

0:010> g
Evaluate expression: 15768 = 00000000`00003d98
 # Child-SP          RetAddr               Call Site
00 000000bb`041febd8 00007ff9`9df0a21f     gdiplus!CopyOnWriteBitmap::CreateHBITMAP
01 000000bb`041febe0 00007ff9`9df0a19a     gdiplus!GpBitmap::CreateHBITMAP+0x3b
02 000000bb`041fec10 00007ff9`72442c61     gdiplus!GdipCreateHBITMAPFromBitmap+0xaa
03 000000bb`041fec50 00007ff9`72439471     System_Drawing_ni+0x72c61
04 000000bb`041fed10 00007ff9`7243940a     System_Drawing_ni!System.Drawing.Bitmap.GetHbitmap+0x51
05 000000bb`041fed70 00007ff9`36d02a75     System_Drawing_ni!System.Drawing.Bitmap.GetHbitmap+0x7a
06 000000bb`041fede0 00007ff9`8d597a47     WindowsFormsApp1!WindowsFormsApp1.Form1.<>c.<button1_Click>b__1_0+0x75
...

三:總結(jié)

說實話,找到程序的 GDI句柄泄露 的前因后果難度系數(shù)還是蠻高的,在沒有系統(tǒng)科學(xué)的工具和基礎(chǔ)知識之前,花費幾天的時間排查這個問題是很正常的,相信這篇文章給后來人少踩坑吧。文章來源地址http://www.zghlxwxcb.cn/news/detail-479885.html

如何洞察 C# 程序的 GDI 句柄泄露

到了這里,關(guān)于如何洞察 C# 程序的 GDI 句柄泄露的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • 記一次奇怪的文件句柄泄露問題

    記錄并分享一下最近工作中遇到的 Too many open files 異常的解決過程。 產(chǎn)品有個上傳壓縮包并導(dǎo)入配置信息到數(shù)據(jù)庫中的功能,主要流程如下: 用戶上傳壓縮包; 后端解壓存放在臨時目錄,并返回列表給用戶; 用戶選擇需要導(dǎo)入哪些信息; 后端按需插入數(shù)據(jù)庫中,完成后刪

    2024年02月05日
    瀏覽(24)
  • RK3588 MPP解碼句柄泄露問題記錄

    RK3588 MPP解碼句柄泄露問題記錄

    最近在用瑞芯微3588開發(fā)板做一個視頻處理的項目,前兩天拷機發(fā)生了閃退,彈出的問題是“打開文件過多”,經(jīng)過初步排查定位到是MPP硬解碼部分出的問題。 我的MPP解碼部分主要用來讀取網(wǎng)絡(luò)相機rtsp流,主要參考了一個github項目GitHub - MUZLATAN/ffmpeg_rtsp_mpp: ffmpeg 拉取rtsp h264流

    2024年02月09日
    瀏覽(24)
  • PerfView專題 (第十五篇): 如何洞察 C# 中的慢速方法

    PerfView專題 (第十五篇): 如何洞察 C# 中的慢速方法

    在 dump 分析旅程中,經(jīng)常會遇到很多朋友反饋一類問題,比如: 方法平時都執(zhí)行的特別快,但有時候會特別慢,怎么排查? 我的方法第一次執(zhí)行特別慢,能看到慢在哪里嗎? 相信有朋友肯定說,加些日志不就好了,大方向肯定是沒問題的,但加日志的顆粒度會比較粗而且侵

    2024年02月16日
    瀏覽(25)
  • PerfView專題 (第十六篇): 如何洞察C#托管堆內(nèi)存的 "黑洞現(xiàn)象"

    PerfView專題 (第十六篇): 如何洞察C#托管堆內(nèi)存的 "黑洞現(xiàn)象"

    首先聲明的是這個 黑洞 是我定義的術(shù)語,它是用來表示 內(nèi)存吞噬 的一種現(xiàn)象,何為 內(nèi)存吞噬 ,我們來看一張圖。 從上面的 卦象圖 來看,GCHeap 的 Allocated=852M 和 Committed=16.6G ,它們的差值就是 分配緩沖區(qū)=16G ,緩沖區(qū)的好處就是用空間換時間,弊端就是會實實在在的侵占內(nèi)

    2024年02月16日
    瀏覽(18)
  • C# wpf 使用GDI+實現(xiàn)截屏

    C# wpf 使用GDI+實現(xiàn)截屏

    第一章 使用GDI+實現(xiàn)截屏(本章) 第二章 使用DockPanel制作截屏框 第三章 實現(xiàn)截屏框熱鍵截屏 第四章 實現(xiàn)截屏框?qū)崟r截屏 第五章 使用ffmpeg命令行實現(xiàn)錄屏 wpf做屏幕錄制或者屏幕廣播之類的功能時需要實現(xiàn)截屏,在C#中比較容易實現(xiàn)的截屏方法是使用GDI+,本文將展示使用G

    2024年02月07日
    瀏覽(18)
  • C# Windows API應(yīng)用:獲取桌面所有窗口句柄的方法

    C# Windows API應(yīng)用:獲取桌面所有窗口句柄的方法 在 C# 的 Windows 應(yīng)用程序開發(fā)中,我們常常需要獲取桌面上所有窗口的句柄,以便進(jìn)行一些窗口管理或者后續(xù)操作。本文將介紹一種利用 Windows API 獲取桌面所有窗口句柄的方法,并提供相應(yīng)的源代碼和描述。 在開始之前,我們需

    2024年02月05日
    瀏覽(39)
  • PerfView 洞察C#托管堆內(nèi)存 "黑洞現(xiàn)象"

    PerfView 洞察C#托管堆內(nèi)存 "黑洞現(xiàn)象"

    首先聲明的是這個 黑洞 是我定義的術(shù)語,它是用來表示 內(nèi)存吞噬 的一種現(xiàn)象,何為 內(nèi)存吞噬 ,我們來看一張圖。 從上面的 卦象圖 來看,GCHeap 的 Allocated=852M 和 Committed=16.6G ,它們的差值就是 分配緩沖區(qū)=16G ,緩沖區(qū)的好處就是用空間換時間,弊端就是會實實在在的侵占內(nèi)

    2024年02月16日
    瀏覽(21)
  • c#獲取句柄,并對第三方軟件的輸入框和按鈕進(jìn)行控制

    c#獲取句柄,并對第三方軟件的輸入框和按鈕進(jìn)行控制

    剛學(xué)了沒多久,還有很多地方?jīng)]有理解到位,還請大家指正。 當(dāng)程序運行起來,就會顯示在任務(wù)管理器中,軟件中的每個事件,比如按鈕,文本框等一些控件,每個事件都會產(chǎn)生一個句柄,句柄就是這些事件的標(biāo)識符。如果拿到句柄就可以自己寫軟件對第三方軟件進(jìn)行控制。

    2024年02月16日
    瀏覽(27)
  • 移動應(yīng)用數(shù)據(jù)安全性:如何防止應(yīng)用程序被黑客攻擊和數(shù)據(jù)泄露?

    移動應(yīng)用數(shù)據(jù)安全性:如何防止應(yīng)用程序被黑客攻擊和數(shù)據(jù)泄露?

    在移動應(yīng)用成為人們生活中不可或缺的一部分的今天,數(shù)據(jù)安全性已經(jīng)成為一個非常重要的問題。隨著黑客攻擊和數(shù)據(jù)泄露事件的頻繁發(fā)生,用戶對于移動應(yīng)用程序的信任度也在逐漸下降。本文將探討移動應(yīng)用數(shù)據(jù)安全性的重要性,并提供一些有效的技術(shù)措施來防止應(yīng)用程序

    2024年02月08日
    瀏覽(38)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包