Windows进程的内核对象句柄表
当一个进程被初始化时,系统要为它分配一个句柄表。该句柄表只用于内核对象 ,不用于用户对象或GDI对象。

创建内核对象
当进程初次被初始化时,它的句柄表是空的。然后,当进程中的线程调用创建内核对象的函数时,比如CreateFileMapping,内核就为该对象分配一个内存块,并对它初始化。这时,内核对进程的句柄表进行扫描,找出一个空项。由于表 3 - 1中的句柄表是空的,内核便找到索引1位置上的结构并对它进行初始化。该指针成员将被设置为内核对象的数据结构的内存地址,访问屏蔽设置为全部访问权,同时,各个标志也作了设置。
下面列出了用于创建内核对象的一些函数(不是个完整的列表):
HANDLE CreateThread(
PSECURITY_ATTRIBUTE psa,
DWORD dwStackSize,
LPTHREAD_START_ROUTINE pfnStartAddr,
PVOID pvParam,
DWORD dwCreationFlags,
PDWORD pdwThreadId);
HANDLE CreateFile(
PCTSTR pszFileNAme,
DWORD dwDesiredAccess,
DWORD dwShareMode,
PSECURITY_ATTRIBUTES psa,
DWORD dwCreationDistribution,
DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile);
HANDLE CreateFileMapping(
HANDLE hFile,
PSECURITY_ATTRIBUTES psa,
DWORD flPRotect,
DWORD dwMaximumSizeHigh,
DWORD dwMaximumSizeLow,
PCTSTR pszName);
HANDLE CreateSemaphore(
PSECURITY_ATTRIBUTES psa,
LONG lInitialCount,
LONG lMaximumCount,
PCTSTR pszName);
用于创建内核对象的所有函数均返回与进程相关的句柄,这些句柄可以被在相同进程中运行的任何或所有线程成功地加以使用。该句柄值实际上是放入进程的句柄表中的索引,它用于标识内核对象的信息存放的位置。 因此当调试一个应用程序且观察内核对象句柄的实际值时,会看到一些较小的值,如1,2等。
每当调用一个将内核对象句柄接受为参数的函数时,就要传递由一个 Create*&函数返回的值。从内部来说,该函数要查看进程的句柄表,以获取要生成的内核对象的地址,然后按定义得很好的方式来生成该对象的数据结构。
如果传递了一个无效索引(句柄),该函数便返回失败,而GetLastError则返回 6(ERROR_INVALID_HANDLE)。由于句柄值实际上是放入进程句柄表的索引,因此这些句柄是与进程相关的,并且不能由其他进程成功地使用。
如果调用一个函数以便创建内核对象,但是调用失败了,那么返回的句柄值通常是0(NULL)。发生这种情况是因为系统的内存非常短缺,或者遇到了安全方面的问题。不过有少数函数在运行失败时返回的句柄值是-1(INVALID_HANDLE_VALUE)。例如,如果CreateFile未能打开指定的文件,那么它将返回INVALID_HANDLE_VALUE,而不是返回NULL。当查看创建内核对象的函数返回值时,必须格外小心。特别要注意的是,只有当调用CreateFile函数时,才能将该值与INVALID_HANDLE_VALUE进行比较。下面的代码是不正确的:
HANDLE hMutex = CreateMutex(...);
if (hMutex == INVALID_HANDLE_VALUE) {
//这段代码不会执行,因为CreateMutex调用失败的时候返回的是NULL
}
同样的,下面的代码也不正确:
HANDLE hFile = CreateFile(...);
if (hFIle == NULL) {
//这段代码不会执行,因为CreateFile调用失败的时候返回的是INVALID_HANDLE_VALUE(-1)
}
关闭内核对象
无论怎样创建内核对象,都要向系统指明将通过调用C l o s e H a n d l e来结束对该对象的操作:
BOOL CloseHandle(HANDLE hobj);
如果该句柄是有效的,那么系统就可以获得内核对象的数据结构的地址,并可确定该结构中的使用计数的数据成员。如果使用计数是0,该内核便从内存中撤消该内核对象。
如果将一个无效句柄传递给CloseHandle,将会出现两种情况之一。如果进程运行正常,CloseHandle返回FALSE,而GetLastError则返回ERROR_INVALID_HANDLE。如果进程正在排除错误,系统将通知调试程序,以便能排除它的错误。
在CloseHandle返回之前,它会清除进程的句柄表中的项目,该句柄现在对你的进程已经无效,不应该试图使用它。无论内核对象是否已经撤消,都会发生清除操作。当调用CloseHandle函数之后,将不再拥有对内核对象的访问权,不过,如果该对象的使用计数没有递减为0,那么该对象尚未被撤消。这没有问题,它只是意味着一个或多个其他进程正在使用该对象。当其他进程停止使用该对象时(通过调用CloseHandle),该对象将被撤消。
假如忘记调用CloseHandle函数,那么会不会出现内存泄漏呢?答案是可能的,但是也不一定。在进程运行时,进程有可能泄漏资源(如内核对象)。但是,当进程终止运行时,操作系统能够确保该进程使用的任何资源或全部资源均被释放,这是有保证的。对于内核对象来说,系统将执行下列操作:当进程终止运行时,系统会自动扫描进程的句柄表。如果该表拥有任何无效项目(即在终止进程运行前没有关闭的对象),系统将关闭这些对象句柄。如果这些对象中的任何对象的使用计数降为0,那么内核便撤消该对象。
因此,应用程序在运行时有可能泄漏内核对象,但是当进程终止运行时,系统将能确保所有内容均被正确地清除。另外,这个情况适用于所有对象、资源和内存块,也就是说,当进程终止运行时,系统将保证进程不会留下任何对象。
参考文献:
- 《Windows核心编程》
Windows进程的内核对象句柄表的更多相关文章
- 【Windows 操作系统】Windows 进程的内核对象句柄表
总结: 1.句柄就是进程句柄表中的索引.2.句柄是对进程范围内一个内核对象地址的引用,一个进程的句柄传给另一个进程是无效的.一个内核对象可用有多个句柄.Windows之所以要设立句柄,根本上源于内存管 ...
- 【Windows 操作系统】 内核对象|句柄
内核对象简介 内核对象就是 一些数据结构该结构用来描述存储内核中的一个内存块中的数据信息. 内存块是一种数据结构,其中的数据成员负责维护该对象的相应信息,这个数据结构以及其中的数据成员只能由内核访 ...
- windows内核对象句柄
内核对象用于管理进程.线程和文件等诸多种类的大量资源,每一个内核对象都只是一个句内存快,它由操作系统内核分配,并只能右操作系统内核访问.这个内存块是一个数据结构,其维护着与对象相关的信息,其中少数成员 ...
- Windows核心编程&内核对象
1. 一个进程在初始化时,系统将会他分配一个空的句柄表,这个句柄表仅供内核对象使用,不供用户对象和GDI对象使用.进程在首次 初始化时,该句柄表为空.句柄表是一个由数据结构组成的数组,包含一个内核对象 ...
- Windows Internals 笔记——内核对象
1.每个内核对象都只是一个内存块,它由操作系统内核分配,并只能由操作系统内核访问.这个内存块是一个数据结构,其成员维护着与对象相关的信息. 2.调用一个会创建内核对象的函数后,函数会返回一个句柄,它标 ...
- 内核对象&句柄&泄漏&检测
今天看到这个问题如何评价王垠的 <讨厌的 C# IDisposable 接口>? - 王垠(人物),答案被歪到windows 内核对象和句柄,答案中谈的太浅显而且有误.翻出陈年老文章(此文 ...
- 内核对象&句柄
目录 1 内核对象的概念 2 内核对象的使用计数 3 句柄 4 句柄表 项目工程代码中设计句柄的使用,一时不知句柄是何物,通过查阅自学之后,对句柄及其使用有一个初步的了解.分享出来,算是抛砖引玉吧 ...
- 内存块是一种数据结构,内核对象&句柄
内核对象&句柄 目录 1 内核对象的概念 2 内核对象的使用计数 3 句柄 4 句柄表 项目工程代码中设计句柄的使用,一时不知句柄是何物,通过查阅自学之后,对句柄及其使用有一个初步的了解. ...
- windows编程之内核对象
学好windows编程,理解内核对象还是至关重要的(●'◡'●).闲话不多说,下面先来了解一下关于内核对象的知识: 内核对象(kernel object):内核对象是用于管理进 ...
随机推荐
- 使用js调用js
直接上源码: <div class="choose"> choose a mode<br> <hr> <button type=" ...
- mysql主从配置,读写分离
Mysql主从配置,实现读写分离 大型网站为了软解大量的并发访问,除了在网站实现分布式负载均衡,远远不够.到了数据业务层.数据访问层,如果还是传统的数据结构,或者只是单单靠一台服务器扛,如此多的数据库 ...
- xshell的一些基本操作
挺全面的一篇文章,没事可以看看. (1)命令ls——列出文件 ls -la 给出当前目录下所有文件的一个长列表,包括以句点开头的“隐藏”文件 ls a* 列出当前目录下以字母a开头的所有文件 l ...
- 创建 .m2 文件夹
首次使用 Maven 创建 .m2 文件夹 1. cmd2. mvn help:system
- JSP FreeMarker Velocity 原理
JSP原理 JSP的运行原理:JSP 本质上是一个Servlet. 每个JSP 页面在第一次被访问时,JSP引擎将它翻译成一个Servlet 程序,然后再把这个 Servlet 源程序编译成Servl ...
- tensorflow学习4-过拟合-over-fitting
过拟合: 真实的应用中,并不是让模型尽量模拟训练数据的行为,而是希望训练数据对未知做出判断. 模型过于复杂后,模型会积极每一个噪声的部分,而不是学习数据中的通用 趋势.当一个模型的参数比训练数据还要多 ...
- vc709时钟信号报单端信号错误的记录
话说,为什么我又要跑去搞fpga玩了,不是应该招个有经验的开发人员么?大概是练度不够吧…… Xilinx这个板子阿,真鸡儿贵,我这还没啥基础,慢慢试吧: 看了乱七八糟各种文档先不提,我还是决定先控制L ...
- [转载]Oracle修改用户表所属表空间的步骤
1 .修改表的空间alter table TABLE_NAME move tablespace TABLESPACENAME 查询当前用户下的所有表选择'alter table'|| table_na ...
- IE haslayout的属性及其值
haslayout是IE 渲染引擎的一个内部组成部分.在IE 中,一个元素要么自己对自身的内容进行计算大小和组织,要么依赖于父元素来计算尺寸和组织内容.为了调节这两个不同的概念,渲染引擎采用了hasl ...
- The Little Prince-12/09
The Little Prince-12/09 今天中文书评+自述奥! 也许世界上也有五千朵和你一模一样的花,但只有你是我独一无二的玫瑰. ————喵喵喵,多么美妙的一句表白词呀! 时间会缓和所有的悲 ...