【Windows 操作系统】 内核对象|句柄
内核对象简介
内核对象就是 一些数据结构该结构用来描述存储内核中的一个内存块中的数据信息。
内存块是一种数据结构,其中的数据成员负责维护该对象的相应信息,这个数据结构以及其中的数据成员只能由内核访问,应用程序是无法访问到的,更别说修改其中的数据成员了。
概念:内核对象可以供系统和应用程序使用来管理各种各样的资源,Windows程序员可以调用Windows API最终调用ntdll.dll中的函数 去创建、打开和操作各种内核对象。常见的内核对象有:访问令牌、事件对象、文件对象、文件映射对象、I/O完成端口、作业对象、邮件槽对象、互斥量对象、管道对象、进程对象、信号量对象、线程对象、可等待计时器对象以及线程池工厂对象等。
个人理解
首先大家别被这个名字唬住了,内核对象=内核+对象;先解释“对象”这个名字,这个与C++中的类的实例是一个道理,即类的实例化便是一个到底,再往底层了说就是按照类这个模板,为其分配一块内存,并作相应的初始化,就这么简单,可别忘了,操作系统也是用代码写成的,只不过不同于C++中的类,而是用的C中的结构体。在一个概念就是“内核”,可别被这玩意整蒙了,这里所谓的内核无非就是跑在系统空间里的实例对象,即对象的内存地址分配在系统空间中的对象即为内核对象。好了,名字的事情搞明白了
内核对象和用户对象相对,由操作系统创建和管理。内核对象的访问时间远大于用户对象。所以创建内核对象的性能损失是比较大的
2、内核对象的构成
我们都知道,像CPP,JAVA,C#等等,这类面向对象的编程语言有一个很重要的特性就是“继承”。所谓的继承一句话总结下就是:拿来主义,子承父业。无非是实现代码复用,而这种复用的语法很 简单,就是通过”继承”来实现了,简化了复用的整个过程。除了复用之外,还有一个好处便是能够实现多态,通过基类指针就能够访问子类中该写过的虚函数,这种基于同一个接口实现不同功能的方式便是多态的核心了。通过一套统一的接口就能够达到统一管理的目的,不得不说,CPP的成功本质是编程思想的成功。然而C语言中,没有继承这个概念,那么多态啥的就跟他没一丁点关系了。难道伟大的C语言真就被这么个小玩意难住了吗?显然没有,诺,这里的内核对象管理就另辟蹊径,把C玩出了CPP的味道,不得不说,C就是这么伟大。微软的解决方案是:
对象头+对象体
对象头便是相当于CPP中的基类,负责管理一些简单的,所有对象共有的属性;诸如进程对象头,线程对象头,文件对象头,调试对象头等等;
对象体相当于CPP中的继承的子类,代表着具体的某个对象;诸如进程对象,线程对象,文件对象,调试对象等等;
具体的内存布局如下图所示:
但别觉得对象头就很简单,类似于CPP中的一个类中有很多字段属性一样,Windows内核中实现的对象头又是有很多个不同的组成部分组成的,这些独立的组成部分是否存在则由一个总的字段来进行管理的,具体的简化图如下图所示:
二.内核对象结构
每个对象都有对象头和对象体组成。所有类型的对象头结构都是相同的,而结构体部分却各不相同的。下面是内核对象的结构图:
一个对象指针总是 指向对象体而不是对象头。如果要访问对象头,需要将对象体指针减去一个特定的偏移值,以获取 OBJECT_HEADER 结构,通过 OBJECT_HEADER 结构定位从而访问其他对象结构辅助信息。对象体内部一般会有一个 type 和一个 size 成员,用来表示对象的类型和大小。
内核对象句柄
通过调用内核对象创建函数(Windows API,如CreateFileMapping)会返回一个内核对象句柄,该句柄的位数与操作系统的位数一致。为了增强操作系统可靠性,句柄与进程相关联(不同进程句柄可以一样)。
句柄是一个指向对象得指针。对象具有唯一性,但是句柄可以有多个,也就是说一个对象可以有多个句柄来引用它,对它进行操作。用来管理命名对象的东西,叫做对象目录
前面讲过句柄与进程相关联,这是通过进程的句柄表来实现的,进程初始化时,系统将为它分配一个句柄表,用以存在内核对象。可以将句柄表看成一个数组,每个数组成员存放一个句柄的相关信息:指向内核对象的指针、一个访问掩码和一些标志。
索引:表示内核对象的信息保存在进程句柄表中的具体位置。
指向内核对象内存块的指针:
访问掩码:访问权限控制,类似网络掩码
访问掩码的功能是以压缩形式描述访问权限。 为简化访问管理,访问掩码包含一组四位(一般权限),这些权限通过使用函数 RtlMapGenericMask转换为一组更详细的权限。
标志:标识子进程是否继承其内核对象。
如何访问这些内核对象(内存块)呢?
操作系统为使用者封装了一组API,使用者可以通过这些API访问内核对象(内存块)。比如,创建内核对象(内存块)时,使用者调用API中的创建内核对象函数,由内核创建一个内核对象(分配一块内存)。
内核对象创建好之后,用一个句柄来标识该内核对象(内存块),这个句柄作为函数值返回。这个句柄就是个整数,32位机句柄就是32bit,64位机句柄就是64bit,同一进程中的任何线程都能使用这个句柄,当需要操作内核对象(内存块)时,通过API将这个句柄传给内核,内核就知道是对哪个内核对象(内存块)进行操作了。
内核中知道了内核对象的地址就可以直接访问这个内核对象了,但是在用户程序中却不能这样访问。Windows为内核对象的访问提供了一系列的函数。当调用一个用于创建内核对象的函数时,函数调用完便返回一个句柄值。句柄值是进程独立的,一个进程中的句柄值在另一个进程中是无效的。
句柄值是一个进程句柄表的索引。每个进程都有一个进程句柄表,而所有进程的句柄表串成一个句柄表链。这个链的头部地址保存在内核变量HandleTableListHead中。
使用计数
内核对象的所有者是操作系统
而非进程,即内核对象的生命周期并不一定会随着创建该对象的进程的消亡而消亡,这一点是通过使用计数来实现的。使用计数是所有内核对象固有的属性,操作系统通过使用计数维护内核对象的生命周期,当使用计数为0的时候,操作系统将销毁该内核对象。内核对象被创建时,其使用计数为1,另一个进程访问该内核对象后,使用计数加1,当进程终止时,使用计数减1。
内核对象类型
内核对象容器
线程内核对象管理方法:
由多条不同类型的链表组织方式
创建和关闭内核对象
当进程首次初始化的时候,其句柄表为空,当进程内的一个线程调用一个会创建内核对象的函数时,操作系统将为这个对象分配并初始化一块内存,然后扫描进程的句柄表,查找到一个空白的记录项,填入该内核对象的相关信息,最后返回对象句柄。可以调用CloseHandle来关闭内核对象句柄,该函数首先检查主调进程的句柄表,验证被关闭的对象句柄值是该经常确实有权访问的一个对象,如果句柄有效,系统将获得内核对象的数据结构地址,并将使用计数减1,如果使用计数变为0,内核对象将被销毁,并从内存中除去。一个内核对象不用了应该调用CloseHandle关闭对象,否则程序运行时将泄漏内核对象,当然,当进程终止后,也能保证内核对象被正确清除。
内核对象结构图
【Windows 操作系统】 内核对象|句柄的更多相关文章
- 【Windows 操作系统】Windows 进程的内核对象句柄表
总结: 1.句柄就是进程句柄表中的索引.2.句柄是对进程范围内一个内核对象地址的引用,一个进程的句柄传给另一个进程是无效的.一个内核对象可用有多个句柄.Windows之所以要设立句柄,根本上源于内存管 ...
- Windows进程的内核对象句柄表
当一个进程被初始化时,系统要为它分配一个句柄表.该句柄表只用于内核对象 ,不用于用户对象或GDI对象. 创建内核对象 当进程初次被初始化时,它的句柄表是空的.然后,当进程中的线程调用创建内核对象的函数 ...
- windows内核对象句柄
内核对象用于管理进程.线程和文件等诸多种类的大量资源,每一个内核对象都只是一个句内存快,它由操作系统内核分配,并只能右操作系统内核访问.这个内存块是一个数据结构,其维护着与对象相关的信息,其中少数成员 ...
- 内核对象&句柄&泄漏&检测
今天看到这个问题如何评价王垠的 <讨厌的 C# IDisposable 接口>? - 王垠(人物),答案被歪到windows 内核对象和句柄,答案中谈的太浅显而且有误.翻出陈年老文章(此文 ...
- 内存块是一种数据结构,内核对象&句柄
内核对象&句柄 目录 1 内核对象的概念 2 内核对象的使用计数 3 句柄 4 句柄表 项目工程代码中设计句柄的使用,一时不知句柄是何物,通过查阅自学之后,对句柄及其使用有一个初步的了解. ...
- 【windows 操作系统】线程句柄HANDLE与线程ID的关系
什么是句柄 句柄是一种指向指针的指针.我们知道,所谓指针是一种内存地址.应用程序启动后,组成这个程序的各对象是住留在内存的.如果简单地理解,似乎我们只要获知这个内存的首地址,那么就可以随时用这个地址访 ...
- 内核对象&句柄
目录 1 内核对象的概念 2 内核对象的使用计数 3 句柄 4 句柄表 项目工程代码中设计句柄的使用,一时不知句柄是何物,通过查阅自学之后,对句柄及其使用有一个初步的了解.分享出来,算是抛砖引玉吧 ...
- [windows操作系统]内核性能剖析
profile这个词有(1)外形.轮廓.外观.形象(2)印象.形象(3)人物简介(4)剖面图.侧面图等意.在计算机和通讯协议中这个词也非常常见.这里主要介绍一下它在软件系统性能分析领域的一个释义. 翻 ...
- Windows中的对象
来源 http://www.0xaa55.com/forum.php?mod=viewthread&tid=1401&extra=page%3D1 windows里常用句柄操作资源 ...
随机推荐
- 一、neo4j中文文档-入门指南
目录 neo4j中文文档-入门指南 Neo4j v4.4 neo4j **Cypher ** 开始使用 Neo4j 1. 安装 Neo4j 2. 文档 图数据库概念 1. 示例图 2.节点 3. 节点 ...
- 申请Namecheap的.me 顶级域名以及申请ssl认证--github教育礼包之namecheap
关于教育礼包的取得见另一篇随笔,在那里笔者申请了digital ocean的vps(虚拟专用主机),跟阿里云差不多,不过个人感觉比阿里云便宜好用一点. 有了自己的主机ip,就想到申请域名,方便好记,也 ...
- Django db使用MySQL连接池
Django db使用MySQL连接池 Sep 25 2016 Django db模块本身不支持MySQL连接池,只有一个配置CONN_MAX_AGE连接最大存活时间,如果WSGI服务器使用了线程池技 ...
- Selenium&PhantomJS 完成爬取网络代理
Selenium模块是一套完整的Web应用程序测试系统,它包含了测试的录制(SeleniumIDE).编写及运行(Selenium Remote Control)和测试的并行处理(Selenimu G ...
- 机器学习-逻辑回归与SVM的联系与区别
(搬运工) 逻辑回归(LR)与SVM的联系与区别 LR 和 SVM 都可以处理分类问题,且一般都用于处理线性二分类问题(在改进的情况下可以处理多分类问题,如LR的Softmax回归用在深度学习的多分类 ...
- linux中sort命令全面解析
目录 一:sort命令作用 二:sort格式 1.sort参数 2.参数解析 sort命令简介 Linux sort 命令用于将文本文件内容加以排序. sort 可针对文本文件的内容,以行为单位来排序 ...
- K8S SVC 转发原理
在前面的文章中,我们已经多次使用到了 Service 这个 Kubernetes 里重要的服务对象.而 Kubernetes 之所以需要 Service,一方面是因为 Pod 的 IP 不是固定的,另 ...
- Redis内存满了怎么办(新年快乐)
Redis内存满了怎么办(新年快乐) 入我相思门,知我相思苦. 长相思兮长相忆,短相思兮无穷极. 一.配置文件 Redis长期使用或者不设置过期时间,导致内存爆满或不足,可以到Redis的配置文件re ...
- c语言之sizeof总结+strlen函数
一.sizeof的概念 Sizeof是C语言的一种单目操作符,如C语言的其他操作符++.–等.它并不是函数.Sizeof操作符以字节形式给出了其操作数的存储大小.操作数可以是一个表达式或括在括号内的类 ...
- python办公自动化系列之金蝶K3自动登录(二)
接上一篇博文python办公自动化系列之金蝶K3自动登录(一),我们接着聊聊利用python脚本实现金蝶K3 Wise客户端自动登录这一需求. 如上图所示,自动选择[组织机构]后,我们还需要驱动[当前 ...