内核对象简介

内核对象就是 一些数据结构该结构用来描述存储内核中的一个内存块中的数据信息。

  内存块是一种数据结构,其中的数据成员负责维护该对象的相应信息,这个数据结构以及其中的数据成员只能由内核访问,应用程序是无法访问到的,更别说修改其中的数据成员了。

概念:内核对象可以供系统和应用程序使用来管理各种各样的资源,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 操作系统】 内核对象|句柄的更多相关文章

  1. 【Windows 操作系统】Windows 进程的内核对象句柄表

    总结: 1.句柄就是进程句柄表中的索引.2.句柄是对进程范围内一个内核对象地址的引用,一个进程的句柄传给另一个进程是无效的.一个内核对象可用有多个句柄.Windows之所以要设立句柄,根本上源于内存管 ...

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

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

  3. windows内核对象句柄

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

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

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

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

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

  6. 【windows 操作系统】线程句柄HANDLE与线程ID的关系

    什么是句柄 句柄是一种指向指针的指针.我们知道,所谓指针是一种内存地址.应用程序启动后,组成这个程序的各对象是住留在内存的.如果简单地理解,似乎我们只要获知这个内存的首地址,那么就可以随时用这个地址访 ...

  7. 内核对象&句柄

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

  8. [windows操作系统]内核性能剖析

    profile这个词有(1)外形.轮廓.外观.形象(2)印象.形象(3)人物简介(4)剖面图.侧面图等意.在计算机和通讯协议中这个词也非常常见.这里主要介绍一下它在软件系统性能分析领域的一个释义. 翻 ...

  9. Windows中的对象

    来源  http://www.0xaa55.com/forum.php?mod=viewthread&tid=1401&extra=page%3D1  windows里常用句柄操作资源 ...

随机推荐

  1. gorm连接mysql的初始化配置

    包含mysql配置.gorm配置.连接池配置.log日志配置 init_db_log.go文件代码 package main import ( "fmt" "gorm.i ...

  2. Go 变量及基本数据类型2

    #### Go 变量及基本数据类型(二)今天学习一下基本数据类型,包括整数类型,小数类型,字符类型##### 整数类型用来存放整数数值的, 如0,1,-10,2222等; 整数型的类型有: 类型 有无 ...

  3. 昔日埋雷不经意,今朝踩雷排查难:JetBrains系列IDE使用SFTP连接远程服务器报“EOF while reading packet”解决方法

    写在前面 这是一篇问题解决记录.希望能帮到遇到同样问题的读者. 强烈建议:请您先看解决步骤一节,如果您发现在下的问题和您的问题不一样,就可以及时离开本文,避免浪费时间. 正文 问题描述 在使用GoLa ...

  4. Pycharm新建文件时头部模板的配置方法

    方法

  5. Vue.js项目的兼容性与部署配置

    一.处理兼容性问题的相关插件: 1> 解决移动端某些版本的浏览器,点击事件有3s延时触发的问题 · 安装 fastclick 依赖包:npm install fastclick --save-d ...

  6. jsp 中 include指令 用法, <%@ include file="..."%> 和 <jsp:include page="..." flush="true" />的区别?

    原文链接https://blog.csdn.net/u012187452/article/details/51779052 1. 什么是jsp 文件? 个人理解.  jsp 是一个容器,可以将我们编写 ...

  7. C++的set重载运算符

    转载: https://www.cnblogs.com/zhihaospace/p/12843802.html set 容器模版需要3个泛型参数,如下: template<class T, cl ...

  8. Codeforces Round #741 (Div. 2)

    全部题目跳转链接 A - The Miracle and the Sleeper 题意 给定\([l, r]\) 求出在这个区间内的两个数字a和b的取模的最大值 (\(a \ge b\)) 分析 上届 ...

  9. 浅谈C#可变参数params

    前言 前几天在群里看到群友写了一个基础框架,其中设计到关于同一个词语可以添加多个近义词的一个场景.当时群友的设计是类似字典的设计,直接添加k-v的操作,本人看到后思考了一下觉得使用c#中的params ...

  10. AGC008 部分简要题解

    F 不妨前考虑 \(70 \%\) 的部分分,\(s\) 全部为 \(1\). 首先可以发现这个问题之所以困难是因为同一个联通子树可能可以被多个中心节点导出. 因此,我们考虑对于一个合法的联通子树,在 ...