- 积分
- 2106
- 最后登录
- 2024-9-12
- 精华
- 1
- 阅读权限
- 220
- 主题
- 289
- UID
- 3081083
- 帖子
- 2717
- PB币
- 98532
- 威望
- 169
- 贡献
- 0
- 技术
- 56
- 活跃
- 2885
这货不是澎湖冰洲
- UID
- 3081083
- 帖子
- 2717
- PB币
- 98532
- 贡献
- 0
- 技术
- 56
- 活跃
- 2885
|
发表于 2020-4-19 12:43:03
IP属地黑龙江
|显示全部楼层
本帖最后由 penghubingzhou 于 2020-12-15 11:49 编辑
接下来,我们就可以来看看系统为我们提供的堆内存分配函数了。在C里面,我们知道我们可以用malloc这个函数动态声明一个内存空间,这个函数会返回一个void类型的指针,我们可以根据自己的需要将这段内存的指针强转成我们需要的任意类型,最后可以再用free函数回收指针指向的内存空间;而在C++里,除了这种方式,我们还多出来一种new/delete运算符的分配/回收方式,来声明或者回收一段堆内存空间。因为IOKit是C++的子集,所以在IOKit里你依然可以用new/delete运算符来分配所需要的堆内存空间(事实上,如果你有查看过xnu的源码,你就会知道每个OSObject对象及其子类对象,在分配时执行的分配函数,本质上就是new运算符的一个高级封装函数,而回收的release和free函数,本质也是delete运算符的一个高级封装函数),而malloc这种方式,在IOKit里被另外一组函数给替代了:IOMalloc函数以及IOFree函数。
首先看下IOMalloc函数的函数原型:
- void * IOMalloc(vm_size_t size) __attribute__((alloc_size(1)));
复制代码
可以看到,这个函数与malloc函数类似,里面的参数只有一个,是一个vm_size_t类型的值,表示要分配的内存空间大小。一般来说,我们分配堆空间都是为了动态声明某类型的需要,所以一般我们可以很轻易地用sizeof操作符来返回一个类型的大小,比如sizeof(3 * uint8_t),这就表示分配3个uint8_t类型的空间大小。注意,这种分配方式,其返回的指针也是一个void类型的,所以,你一般还需要配合一步强转操作,来把你所需要的空间的指针转换成你真正使用类型的指针,比如我们在某个驱动的start函数里写了如下的代码:
- ......
- uint8_t* mm;
- ......
- mm = (uint8_t*)IOMalloc(sizeof(uint8_t));
-
- if (!mm){
- IOLog("%s::allocate memory failed!\n", getName());
- return false;
- }
- ......
复制代码
其中省略号表示省略的若干代码。这段代码就是一个使用IOMalloc的经典例子,它声明了一个uint8_t类型的指针mm,并在运行过程中动态分配了它所指向的堆空间内存,大小就是uint8_t类型的大小。需要注意的是,堆内存分配可能出现内存满等问题而导致分配失败,因此我们有必要在后面紧跟一步判断,通过判指针是否为空的方式判断是否正确分配了内存,如果分配失败,则应打印错误信息,并且返回错误值。
另外值得注意的是,这种分配方式不会保证对齐内存,并且不保证线程安全,因此在中断级别且持有简单锁的代码上下文里,你不应该使用这种分配方式。
与这个函数对应的回收函数就是IOFree了,它的函数原型如下:
- void IOFree(void * address, vm_size_t size);
复制代码
这个函数是一个无返回值函数,它有两个参数:第一个参数是采用IOMalloc函数分配的内存空间的指针,第二个则表示要释放的内存值。这个函数会强制释放我们用IOMalloc函数分配的内存空间,同样,它也不可以在持有简单锁的中断代码上下文调用。
比如刚才的例子,我们现在要在stop函数里对空间进行回收,则代码执行如下:
- .....
- if(mm){
- IOFree(mm, sizeof(uint8_t));
- mm = NULL;
- }
- ......
复制代码
其中省略号表示省略的若干代码。这段代码执行后,系统就会判断mm指向的内存是否存在,如果存在,就会回收并释放mm指针指向的那片大小为uint8_t类型大小的内存空间,这段内存就会重新回归系统怀抱等待下次的分配与调用。需要注意的是,虽然这段堆内存空间已经得到了回收,此段内存相对于驱动而言已经成为“非法内存”,但其中的数据依然是存在的(我们称此时这段内存存储的数据为“脏数据”),而此时mm指针所持有的内存地址依然指向这段“非法内存”。此时我们称mm这个指针是“野指针”。野指针的危害有时候要比内存泄漏还要严重,它会导致对系统内存的非法访问,严重的甚至会遗留安全漏洞给黑客提供攻击提权的机会。为了避免野指针的出现,我们要养成一个良好的习惯,即:释放完堆空间之后,就把堆空间释放产生的野指针置空,避免留下安全隐患。
除了IOMalloc这种分配方式外,IOKit还提供了OSMalloc的分配方式,有兴趣的同学可以自行翻阅IOKit的相关头文件,这里不再赘述。需要注意,每个分配函数与释放函数在使用时必须配套对应,不得串用混用!!!!!
|
|