一个“反问”引发的内存反思

大家好,好久不见,最近正好有个iOS内存问题与大家分享

今天,论坛上有人突然发问,对线程ID获取方式提出内存风险🤔,

作为内存方面的兴趣爱好者,第一时间凑了过来。。。🧐

问题很简单,主要在于获取线程ID的方式,做iOS的同学比较熟悉,一般来说是用:

[NSThread currentThread];

但在一些底层功能实现时,仅仅依靠OC层时不够的,特别是在做一些HOOK,或者捞取一些系统数据时,还需要C/C++的实现,比如:

https://stackoverflow.com/questions/1540603/mac-iphone-is-there-a-way-to-get-a-thread-identifier-without-using-objective-c 有趣的是,这个问题下面,也有同学提出了类似的问题,

pthread_mach_thread_np(pthread_self()) 和mach_thread_self()都是获取当前线程的ID,那两个效果是否一样呢?

首先,看.h文件

根据定义,我们发现pthread_mach_thread_np主要是将pthread_t的类型转换成mach_port_t类型,这里有个知识点,线程的类别,主要可分为三种 1.glibc库的线程id。实际上是线程控制块tcb首地址;2.内核级线程id,系统唯一;3.mac os特有的id。实际上不能说是thread id,而应该当做是端口

https://blog.csdn.net/yxccc_914/article/details/79854603 这篇文章进行了一个简单的讲解,里面也有一些链接讲性能获取的内容,大家可以参考

而mach_thread_self看起来就是直接获取自身的mach_port_t端口号

至于NSThread 与上面两这个关系,这里推荐两篇文章

https://blog.csdn.net/weixin_34268610/article/details/87963492这里主要是讲BSBacktraceLogger 这个轻量级的框架的源码,里面对NSThread和pthread进行了研究。

另一个是http://www.cocoachina.com/articles/11970,这个主要是讲RunLoop原理的,里面也有相关的内容

这两篇文章本身知识点密集,推荐有空的同学看一下,下面言归正传

既然看.h文件看不出来,只能找找案例或者源码、官方文档

(这个过程很辛苦。。。由于一些原因,没有梯子可以用,我在baidu浪费了几个小时没有任何结果,在快要崩溃的边缘终于在bing搜索找到了答案。。。在线推荐bing一波)

首先看一个案例(截图来源于网络搜索,如有侵权请告知)

https://codereview.chromium.org/276043002/

在某项目的CR过程中,评审人不推荐使用mach_thread_self(),原因是需要mach_port_deallocate()配对释放,而使用pthread_mach_thread_np(pthread_self())调用时线程池的缓存,不需要mach_port_deallocate()进行释放,同时,配对使用mach_thread_self()和mach_port_deallocate()进行两次系统调用,而pthread_mach_thread_np(pthread_self())只是调用了两次libc function,更加轻量。

又进了一步,再去查查文档,由于是mach层的内容,我这边直接找了gnumach的文档,毕竟看操作系统级的代码还是要看对应的文档更靠谱。

http://www.gnu.org/software/hurd/gnumach-doc/Thread-Information.html

这里写明了,mach_thread_self()会增加当前内容的引用计数,这里就跟OC的内存机制很像,OC就是通过引用计数机制对内存进行管理,每次指针引用它,计数就会加一,使用完成后,需要手动释放,当引用计数为零时,就会释放这个内存,这里应该可以类比,值得注意的是后面这段话,这里确保的方法的稳定性,毕竟底层方法的调用,稳定性是大家十分关心的。

再看看mach_port_deallocate()的定义

http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/mach_port_deallocate.html

确实是用于减少引用计数

另外,在查找的过程中,偶然间在KSCRASH框架源码中找到了下面内容

https://github.com/kstenerud/KSCrash

第一张是对mach_thread_self()的提醒,第二张是对mach_thread_self()进行了封装,防止出现没有配对的现象,KSCRASH本身就是获取crash信息的第三方插件,自身的稳定性不言而喻,既然这趟封装,说明用了就释放对稳定性没有影响。

有文档,有案例,基本可以石锤了。

总结

mach_thread_self()是一个稳定的获取线程ID的方法,但需要跟mach_port_deallocate()配对使用,不然可能会引发内存常驻

pthread_mach_thread_np(pthread_self())不要系统调用,也不要配对使用,推荐优先使用

如果因一些原因一定要使用mach_thread_self(),可以学习kscrash进行封装。

 

课外拓展:

getid()和pthread_self()区别

https://stackoverflow.com/questions/6372102/what-is-the-difference-between-pthread-self-and-gettid-which-one-should-i-u

https://www.cnblogs.com/jaydenhpj/p/5200062.html

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值