`

内核对象和句柄的介绍及注意事项

 
阅读更多

                                                               内核对象,句柄

       系统会创建几种类型的内核对象,比如访问令牌对象、事件对象、文件对象、文件映射对象、I\O完成端口对象、作业对象、邮件槽对象、互斥量对象、管道对象、进程对象、信号量对象、线程对象、可等待计时器对象、线程池工厂对象等。

       每个内核对象都只是一个内存块,它由操作系统内核分配,并只能由操作系统内核访问。这个内存块是一个数据结构,其成员维护着与对象相关的信息。

       由于内核对象的数据结构只能由操作系统内核访问,所以应用程序不能在内存中定位这些数据结构并直接更改其内容。microsoft有意识强化了这个限制,确保内核对象结构保持一致性状态。

       调用一个会创建内核对象的函数后,函数会返回一个句柄(handle),它标识了所创建的对象。可以将这个句柄想象为一个不透明的值,它可由进程中的任何线程使用。在32位 windows进程中,句柄是一个32位的值;在64位windows进程中,则是一个64位的值。

       为了增强操作系统的可靠性,这些句柄值是与进程相关的。所以,如果将句柄值传给另一个进程中的线程(通过某种进程间通信方式),那么另一个进程用我们的进程的句柄值来发出调用时,就有可能失败;甚至更糟糕的是,它们会根据该句柄在我们的进程句柄表的索引来引用另一个进程中的完全不同的内核对象。

 

       内核对象的所有者是操作系统内核,而非进程。  如果我们的进程调用了一个函数创建了一个内核对象,然后进程终止运行,则内核对象并不一定会销毁。大多数情况下,这个内核对象是会销毁的,但假如另一个进程正在使用我们的进程创建的内核对象时,那么在其他进程停止之前,这个内核对象时不会销毁的。总之,内核对象的生命周期可能长于创建它的那个进程。

 

       操作系统内核知道当前有多少个进程正在使用一个特定的内核对象,因为每个对象都包含了一个使用计数。如果一旦对象的使用计数变成0,操作系统内核就会销毁对象。

 

进程的句柄表结构

包括  索引,指向内核对象内存块的指针,访问掩码(包含标志位的一个DWORD),标志

 

       创建线程,文件,文件映射,信号量等,这些用于创建内核对象的任何函数都会返回一个与进程相关的句柄,这个句柄可由用一个进程中运行的所有线程使用。

 

       调用一个函数时,如果它接受一个内核对象句柄作为参数,就必须把Create* 函数返回的值传递给它。在内部,这个函数会查找进程的句柄表,获得目标内核对象的地址,然后以一个恰当的方式来操纵对象的数据结构。

 

       凡是用于创建内核对象的函数,在检查他们的返回值时,务必相当仔细。

       在只有调用CreateFile时,才能将它的返回值与INVALID_HANDLE_VALUE进行比较。

       而其他Create* 调用通常是返回NULL的   

       所以比较时,应注意

 

关闭内核对象

       应注意,如果传给CloseHandle函数的是一个无效的句柄,那么可能发生以下两种情况之一:

       如果进程是正常运行的,CloseHandle将返回FALSE,而GetLastError返回RROR_INVALID_HANDLE。如果进程正在被调试,那么系统将跑出0xC0000008异常(指定了无效的句柄),便于我们调试这个错误。

就在CloseHandle函数返回之前,它会清除进程句柄中对应的记录项——这个句柄现在对我们的这个进程已经无效了,不要在试图用它。无论内核对象当前是否被销毁,这个清除操作过程都会发生的! 一旦调用了CloseHandle,我们的进程就不能访问那个内核对象;但是,如果对象的使用计数还没有递减至0,它就不会被销毁。这是完全正常的;它表明另外还有一个或多个进程在使用该对象。当其他进程(通过调用CloseHandle)全部停止使用这个对象后,对象就会被销毁。

 

       如果忘记调用CloseHandle,不一定会发生对象的泄漏情况。

       在进程运行期间,进程可能发生资源泄漏的情况。

       但是,当进程终止运行,操作系统会确保此进程使用的所有资源都被释放——这是可以保证的!

       对于内核对象,操作系统执行的是以下操作:

       进程终止时,系统自动扫描该进程的句柄表。如果这个表中有任何有效的记录项(即进程终止前没有关闭的对象),操作系统会为我们关闭这些对象句柄。只要这些对象中有一个的使用计数递减至0,内核就会销毁对象。

 

       所以在应用程序运行时,它可能会泄漏内核对象;但当进程终止运行,系统能保证一切都被正确清除。

 

       如何查看内核对象?   windows任务管理器    选择  查看->选择列->选择进程页列,指定在进程选项卡中显示句柄数列。

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics