1. 什麼是核心對象?
核心對象是作業系統分配的一個記憶體塊,該記憶體塊是一個資料結構,用於管理對象的各種資訊。
當應用程式要與系統裝置進行互動的時候,將使用到核心對象,出於安全的考慮,進程是不能直接存取核心對象的,作業系統提供了對應的函數來對它們進行訪問。
存取符號對象、事件對象、檔案對象、工作物件、互斥對象、管道對象、等待計時器對象等都是核心對象。我們在編程時經常要建立、開啟和操作它們。
核心對象由核心擁有,並不是進程所擁有,每個核心對象都有一個計數器來儲存有多少個進程在使用它的資訊。進程調用時,計數器增1,調用結束,計數器減1,核心對象計數器為零時,銷毀此核心對象.
核心對象有安全性描述元的保護,安全性描述元描述了誰建立了該對象以及誰能夠使用該對象。用於建立核心對象的函數幾乎都有一個指向SEC URITY_ATTRIBUTES 結構的指標作為其參數。
大多數應用程式通過傳NULL值建立具有預設安全性的對象。如果想限制別人對對象的訪問,就需要單獨建立一個SECURITY_ATTRIBUTES對象並對其初始化。
2. 什麼是控制代碼?
通俗的概念:控制代碼是WONDOWS用來標識被應用程式所建立或使用的對象的唯一整數,WINDOWS使用各種各樣的控制代碼標識諸如應用程式執行個體,視窗,控制,位元影像,GDI對象等等。當應用程式訪問核心對象時,將返回一個標示核心對象的東東,這些則是控制代碼。核心對象的“控制代碼”,可以惟一地標誌對象。當應用建立核心對象時,返回的就是控制代碼。此核心對象進程的所有線程都可以利用這個控制代碼訪問核心對象。
3. 核心對象建立?
當利用creat*函數如creatfilemapping來建立核心對象時,調用該函數的時候核心就為該對象分配一個記憶體塊,並進行初始化,然後核心再掃描該進程的控制代碼表,初始化一條記錄並放在控制代碼表中。所謂的控制代碼表是指每個進程在被初始化的時候,將被分配一個控制代碼表,該控制代碼表將儲存核心對象的控制代碼,該控制代碼表包含三個內容:核心物件控點,核心物件控點地址,訪問屏蔽標誌。
4. 關閉核心對象
無論進程怎樣建立核心對象,在不使用該對象的時候都應當通過Bool CloseHandle(HANDLE hobj)來向作業系統聲明結束對該對象的訪問。
這裡有一個問題:為什麼結束進程能釋放所有佔用的資源?
是因為進程在運行時有可能出現記憶體泄露。在進程終止運行時,系統會自動掃描進程的控制代碼表。若表中擁有任何無效項目(進程終止前沒關閉的對象),系統將關閉這些對象的控制代碼。對象的計數器被置0,核心便會撤銷這些對象。
5. 如何發現和分析控制代碼泄露?
經上面的瞭解知道當應用程式使用完核心對象之後需要釋放資源關閉核心對象。如果沒用CloseHandle,那麼將可能導致當前進程無法再開啟對應的核心對象,而從系統層面上來說將會大量佔用記憶體,導致系統變慢。所以有時候發現應用程式進程本身佔用記憶體不多,但是系統記憶體佔用卻很高,可能就因為控制代碼泄露導致。
下面簡單介紹兩種判斷控制代碼泄露的方法:
1)、開啟工作管理員:選擇菜單:查看—選擇列,勾上“控制代碼數“,如:
此時工作管理員中多了一列控制代碼數,如果你發現一個進程控制代碼數在不斷增加,那麼可能該進程就存在記憶體泄露了。
2)使用工具Process Explorer,該工具能夠非常明了的看到進程所正在使用的核心對象,當存在控制代碼對象時,它能夠協助你分析找到原因。下面以一個存在控制代碼泄露的簡單程式為例:
該程式在訪問1.txt這個檔案的時候,沒有關閉控制代碼,導致檔案不斷被開啟。
從這裡你還可以看到有GDI handles和USER Handles的概念,我理解為這些handle可以統稱為核心對像的handle,只是對應了不同的內容,handles直接操作檔案,註冊表這類東西,而gdi與user操作的是可見的這些東西,gdi與user又有細份,gdi更關注圖形,而user更關注互動。
vivilisa 03.09.2009