总结:

1、句柄就是进程句柄表中的索引。
2、句柄是对进程范围内一个内核对象地址的引用,一个进程的句柄传给另一个进程是无效的。一个内核对象可用有多个句柄。
Windows之所以要设立句柄,根本上源于内存管理机制的问题,即虚拟地址。简而言之数据的地址需要变动,变动以后就需要有人来记录、管理变动,因此系统用句柄来记载数据地址的变更。

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

。第一个句柄索引为4,第二个是8。

创建内核对象

当进程初次被初始化时,它的句柄表是空的。然后,当进程中的线程调用创建内核对象的函数时,比如 CreateFileMapping,内核就为该对象分配一个内存块,并对它初始化。这时,内核对进程的句柄表进行扫描,找出一个空项。由于表 3 - 1 中的句柄表是空的,内核便找到索引 4位置上的结构并对它进行初始化。该指针成员将被设置为内核对象的数据结构的内存地址,访问屏蔽设置为全部访问权,同时,各个标志也作了设置。

下面列出了用于创建内核对象的一些函数(不是个完整的列表):

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);

用于创建内核对象的所有函数均返回与进程相关的句柄,这些句柄可以被在相同进程中运行的任何或所有线程成功地加以使用。该句柄值实际上是放入进程的句柄表中的索引,它用于标识内核对象的信息存放的位置。 因此当调试一个应用程序且观察内核对象句柄的实际值时,会看到一些较小的值,如 4,8 等。

每当调用一个将内核对象句柄接受为参数的函数时,就要传递由一个 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,那么内核便撤消该对象。

因此,应用程序在运行时有可能泄漏内核对象,但是当进程终止运行时,系统将能确保所有内容均被正确地清除。另外,这个情况适用于所有对象、资源和内存块,也就是说,当进程终止运行时,系统将保证进程不会留下任何对象。

作者:Akkuman
链接:https://ld246.com/article/1518194894673
来源:链滴
协议:CC BY-SA 4.0 https://creativecommons.org/licenses/by-sa/4.0/

【Windows 操作系统】Windows 进程的内核对象句柄表的更多相关文章

  1. Windows进程的内核对象句柄表

    当一个进程被初始化时,系统要为它分配一个句柄表.该句柄表只用于内核对象 ,不用于用户对象或GDI对象. 创建内核对象 当进程初次被初始化时,它的句柄表是空的.然后,当进程中的线程调用创建内核对象的函数 ...

  2. windows内核对象句柄

    内核对象用于管理进程.线程和文件等诸多种类的大量资源,每一个内核对象都只是一个句内存快,它由操作系统内核分配,并只能右操作系统内核访问.这个内存块是一个数据结构,其维护着与对象相关的信息,其中少数成员 ...

  3. 【Windows 操作系统】 内核对象|句柄

    内核对象简介 内核对象就是 一些数据结构该结构用来描述存储内核中的一个内存块中的数据信息.   内存块是一种数据结构,其中的数据成员负责维护该对象的相应信息,这个数据结构以及其中的数据成员只能由内核访 ...

  4. Windows API学习---线程与内核对象的同步

    前言 若干种内核对象,包括进程,线程和作业.可以将所有这些内核对象用于同步目的.对于线程同步来说,这些内核对象中的每种对象都可以说是处于已通知或未通知的状态之中.这种状态的切换是由Microsoft为 ...

  5. Windows核心编程笔记之内核对象

    0x01 子进程继承父进程内核对象句柄 父进程 #include <Windows.h> #include <iostream> #include <strsafe.h& ...

  6. 内核对象&句柄&泄漏&检测

    今天看到这个问题如何评价王垠的 <讨厌的 C# IDisposable 接口>? - 王垠(人物),答案被歪到windows 内核对象和句柄,答案中谈的太浅显而且有误.翻出陈年老文章(此文 ...

  7. 内核对象&句柄

    目录 1 内核对象的概念 2 内核对象的使用计数 3 句柄 4 句柄表   项目工程代码中设计句柄的使用,一时不知句柄是何物,通过查阅自学之后,对句柄及其使用有一个初步的了解.分享出来,算是抛砖引玉吧 ...

  8. 内存块是一种数据结构,内核对象&句柄

    内核对象&句柄 目录 1 内核对象的概念 2 内核对象的使用计数 3 句柄 4 句柄表   项目工程代码中设计句柄的使用,一时不知句柄是何物,通过查阅自学之后,对句柄及其使用有一个初步的了解. ...

  9. 【windows 操作系统】进程控制块(PCB)

    转载地址:https://blog.csdn.net/qq_38499859/article/details/80057427一.目录文章目录    操作系统3 ----进程控制块(PCB)详解    ...

随机推荐

  1. 2022年最新黑苹果monterey安装efi分享

    最新版本monterey 12.1 安装. 配置: 名称 型号 备注 主板 Gigabyte Z490M Gaming X   内存 威刚万紫千红DDR4 2666 16G x 2 两条16G  插2 ...

  2. Device or resource busy

    格式化磁盘显示忙碌,如何解决呢? [root@jp33e503-11-8 ~]# mkfs.xfs /dev/sdc mkfs.xfs: cannot open /dev/sdc: Device or ...

  3. 一起玩转玩转LiteOS组件:TinyFrame

    摘要:TinyFrame是一个简单的用于解析串口(如 UART.telnet.套接字等)通信数据帧的库. 本文分享自华为云社区<LiteOS组件尝鲜-玩转TinyFrame>,作者:Lio ...

  4. django之分页算法实现(Paginator)

    导入模块:from django.core.paginator import Paginator 一.Paginator的基本用法: from django.core.paginator import ...

  5. vscode配置golang开发环境

    软件: go1.16.5.windows-amd64.msi vscode go安装后已经自动配置相关环境变量.在cmd中用go env查看环境变量. vscode设置goroot和gopath 找到 ...

  6. 10分钟了解代码命名规范(Java、Python)

    前言 关于代码命名,我相信是经常困扰很多小伙伴的一个问题,尤其是对于强迫症晚期患者.怎么说呢,每次小编在写代码之前,总会在想啊想啊,用什么命名法好呢?对于经常在C++.Java.Python等主流语言 ...

  7. JS Map与Set

    笔记整理自:廖雪峰老师的JS教程 Map JavaScript的对象有个小问题,就是键必须是字符串.但实际上Number或者其他数据类型作为键也是非常合理的. 为了解决这个问题,最新的ES6规范引入了 ...

  8. js 对象的深克隆

    前端笔试或者面试的时候,很喜欢问的一个问题就是对象的深度克隆,或者说是对象的深度复制.其实这个问题说容易很容易,但是要说全面也挺不易. 要弄明白对象的克隆,首先要明白js中对象的组成.在js中一切实例 ...

  9. vue单页面应用打包后相对路径、绝对路径相关问题

    原文链接:  vue单页面应用打包后相对路径.绝对路径相关问题展开       在项目开发过程中,在部署过程中,用到了反向代理,这就要求前端代码中不能使用绝对路径.但是我们知道,一般情况下,通过web ...

  10. kubernetes基础——1.基本概念

    一.kubernetes特性 自动装箱,自我修复,水平扩展,服务发现和负载均衡,自动发布和回滚,密钥和配置管理,存储编排,批量处理执行. 二.kubernetes cluster Masters * ...