
要想探索objc的底层原理,首先得初始化对象
YDLog(@"alloc 探索");
YDPerson *p1 = [YDPerson alloc];
YDPerson *p2 = [p1 init];
YDPerson *p3 = [p1 init];
YDPerson *p4 = [YDPerson alloc];
NSLog(@"%@-%p-%p",p1,p1,&p1);
NSLog(@"%@-%p-%p",p2,p2,&p2);
NSLog(@"%@-%p-%p",p3,p3,&p3);
NSLog(@"%@-%p-%p",p4,p4,&p4);
alloc 探索
2021-06-21 10:34:51.956810+0800 001-alloc&init探索[2083:53572] <YDPerson: 0x600003c40350>-0x600003c40350-0x7ffeedff4078
2021-06-21 10:34:51.956985+0800 001-alloc&init探索[2083:53572] <YDPerson: 0x600003c40350>-0x600003c40350-0x7ffeedff4070
2021-06-21 10:34:51.957089+0800 001-alloc&init探索[2083:53572] <YDPerson: 0x600003c40350>-0x600003c40350-0x7ffeedff4068
2021-06-21 10:34:51.957222+0800 001-alloc&init探索[2083:53572] <YDPerson: 0x600003c40360>-0x600003c40360-0x7ffeedff4060

alloc开辟了内存空间init没有对指针进行操作(指针p1、p2、p3指向了同一片内存区域)p1、p2、p3每个相差8字节在栈里是连续的)问题
alloc开辟了内存空间,他是怎么做到的呢?class和objc是怎样进行关联的呢?init又有什么用呢?点击跳转查看alloc的实现,发现alloc是NSObject.h文件的一个函数声明且没实现
首先要探索alloc,在alloc处打下一个断点并运行
xode断点调试工具+符号断点control健,同时点击Xcode日志调试工具的step into,接着会来到汇编里,然后查找这个方法添加符号断点,流程图如下:



通过step into跟流程会来到objc_alloc,对objc_alloc下符号断点,确定objc_alloc属于libobjc.A.dylib库
Debug下的Debug Workflow接着选择 Always Show Disassembly



通过汇编代码查看alloc在底层调用了objc_alloc,然后对objc_alloc下符号断点,发现objc_alloc属于libobjc.A.dylib库
alloc下断点

alloc断点发现alloc归属于libobjc.A.dylib库通过以上三种下断点的方式发现,alloc的调用都会来到同一个库libobjc.A.dylib,即objc的底层源码,"很不幸"在苹果开源网站opensource中找到了libobjc的底层源码。那么就开启objc底层原理的探索吧!

通过对 objc源码全局搜索找到了alloc的实现,但是断点alloc时先调用了objc_alloc然后调用了callAlloc但没有走_objc_rootAllocWithZone,而是直接走的objc_msgSend发送了一个alloc的消息,然后来到了alloc的实现,接着执行_objc_rootAlloc然后又来到了callAlloc,接着执行了_objc_rootAllocWithZone,最后返回
问题
callAlloc为什么会执行两次?后面章节来补充_objc_rootAlloc、callAlloc、 _objc_rootAllocWithZone但执行_objc_rootAlloc后直接调用了_objc_rootAllocWithZone其中的callAlloc直接被跳过了 why?编译器优化

首先通过一个案例来测试,打开汇编模式

通过汇编代码发现变量a和b的值10和20通过寄存器进行了存储用并调用了ydSum函数,(真机测试)为什么是w而不是x呢,arm64不应该是x吗?因为x代表64位,如果用一个64位的寄存器存储一个int值是非常浪费的,这是编译器低位兼容的优化


重新运行两次代码发现代码少了很多并且在最后一次发现ydSum没有了,编译器直接将结果算好了存储在w8里面了,这就是编译器的优化,同时验证了为什么callAlloc为什么被跳过的原因。
编译器的优化设置如下


那alloc又做了什么呢?

打开objc底层源码文件,并在main.m主函数中创建YDPerson对象,YDPerson继承于NSObject,且不添加任何属性或成员变量,因为上面通过下符号断点推断出了callAlloc函数内的执行流程,在YDPerson初始化时打下断点,因为有了源码更方便调试,直接在callAlloc下断点并运行,最终会进入一个非常重要的函数_class_createInstanceFromZone
通过函数名也可发现这是创建一个实例对象的函数,那创建对象需要开辟多大的内存空间呢?我们一直说obj是关于某一个类的对象,那么创建出来的对象和类是怎么进行关联?进入函数_class_createInstanceFromZone

在函数内首先看到了第一个函数instanceSize,获取实例变量大小

函数会先判断是否有快速缓存实例变量大小,如果有则直接返回缓存中的实例变量的大小并且返回前做16字节对齐,如果没有则会进入到alignedInstancesize中,会执行下面的流程`alignedInstanceSize




word_align会将未经过对齐的实例变量大小即编译好的干净内存的实例变量的大小进行字节对齐,进入word_align,发现里面是一个算法 (x + WORD_MASK) & ~WORD_MASK,这是什么玩意?


案例中YDPerson是继承于NSObject,NSObject有一个Class 类型的成员变量isa,Class又是struct objc_class *类型,因为结构体指针为8字节,所以YDPerson的实例变量大小为8,那么为什么要(x + WORD_MASK) & ~WORD_MASK这样来一下呢?
由于__LP64__ 的WORD_MASK等于7,(x + WORD_MASK) & ~WORD_MASK就等同于 (8+7)& ~7即 15 & ~7换算成二进制0000 1111 & ~0000 0111等价于 0000 1111 & 1111 1000 等于 0000 1000 就等于8 ,也就是说成员变量之间的排序以8字节对齐,那么为什么要以8字节对齐而不是16、32呢?
假设对象内有三个成员变量8字节的name,4字节的age,1字节的sex,那么cpu在读取name时需要先以8字节的大小才能读取到name,读取age时又得改变成4字节,读取sex时又得改变成1字节,在读取时频繁的更改读取的字节数是非常消耗性能的,而在对象的成员变量中没有超过8字节的变量,那么通过8字节的对齐使得访问name是8字节,age也是8字节,sex也是8字节,这样读取时间就大大的缩短了,即通过时间换取空间,那age和sex都占8字节那不是很浪费内存吗?其实苹果在底层还做了内存的优化,通过下面的案例测试


可以发现sex和age共用了一个8字节,说明系统的确对内存进行了优化,那为什么从快速缓存获取实例变量的大小又需要16字节对齐呢?请看后面的篇章结构体的内存对齐
在ruby2.0.0/247或head上试过这个:require'objspace'ObjectSpace.trace_object_allocations->undefinedmethod`trace_object_allocations'forObjectSpace:Module文档说它应该可以工作http://www.ruby-doc.org/stdlib-2.0/libdoc/objspace/rdoc/ObjectSpace.html知道我错过了什么吗? 最佳答案 对于更高的ruby版本,您仍然可能会遇到如下错误:
文章目录认识unity打包目录结构游戏逆向流程Unity游戏攻击面可被攻击原因mono的打包建议方案锁血飞天无限金币攻击力翻倍以上统称内存挂透视自瞄压枪瞬移内购破解Unity游戏防御开发时注意数据安全接入第三方反作弊系统外挂检测思路狠人自爆实战查看目录结构用il2cppdumper例子2-森林whoishe后记认识unity打包目录结构dll一般很大,因为里面是所有的游戏功能编译成的二进制码游戏逆向流程开发人员代码被编译打包到GameAssembly.dll中使用il2ppDumper工具,并借助游戏名_Data\il2cpp_data\Metadata\global-metadata.dat
我错过了什么?我正在尝试使用Active资源的休息服务,我有以下内容:classUser"Test",:email=>"test.user@domain.com")puserifuser.saveputs"success:#{user.uuid}"elseputs"error:#{user.errors.full_messages.to_sentence}"end以及用户的以下输出:#"Test","email"=>"test.user@domain.com"}>和这个错误:/Library/Ruby/Gems/1.8/gems/activeresource-3.0.10/lib/ac
前言 Slowloris攻击是我在李华峰老师的书——《MetasploitWeb 渗透测试实战》里面看的,感觉既简单又使用,现在这种攻击是很容易被防护的啦。不过我也不敢真刀实战的去试,只是拿个靶机玩玩罢了。 废话还是写在结语里面吧。(划掉)结语可以不看(划掉)Slowloris攻击的原理 Slowloris是一种资源消耗类DoS攻击,它利用部分HTTP请求进行操作。也叫做慢速攻击,这里的慢速并不是说发动攻击慢,而是访问一条链接的速度慢。Slowloris攻击的功能是打开与目标Web服务器的连接,然后尽可能长时间的保持这些连接打开。如果由多台电脑同时发起Slo
目录一、原理部分1、什么是串行通信(1)并行通信与串行通信(2)串行通信的制式(3)串行通信的主要方式 2、配置串口(1)SCON和PCON:串行口1的控制寄存器(2)SBUF:串行口数据缓冲寄存器 (3)AUXR:辅助寄存器编辑(4)ES、PS:与串行口1中断相关的寄存器(5)波特率设置 3、串口框架编写二、程序案例一、原理部分1、什么是串行通信(1)并行通信与串行通信微控制器与外部设备的数据通信,根据连线结构和传送方式的不同,可以分为两种:并行通信和串行通信。并行通信:数据的各位同时发送与接收,每个数据位使用一条导线,这种方式传输快,但是需要多条导线进行信号传输。串行通信:数据一位一
是否有操作系统中立的方式让Ruby将键盘和鼠标事件发送到底层操作系统?(对我而言)一个明显的方法是使用Ruby/Java绑定(bind)并使用java.awt.Robot,但这看起来很愚蠢。 最佳答案 对于Mac:geminstallrb-appscript然后你可以用这样的脚本来测试它:require"rubygems"require"appscript"includeAppscriptapp("TextEdit").activateapp("SystemEvents").keystroke("LookMa,keystrokes!
例如,我一直看到称为String#split的方法,但从未见过String.split,这似乎更合乎逻辑。或者甚至可能是String::split,因为您可以认为#split位于String的命名空间中。当假定/隐含类(#split)时,我什至单独看到了该方法。我知道这是ri中识别方法的方式。哪个先出现?例如,这是为了区分方法和字段吗?我还听说这有助于区分实例方法和类方法。但这从哪里开始呢? 最佳答案 不同之处在于您如何访问这些方法。类方法使用::分隔符来表示消息可以发送到类/模块对象,而实例方法使用#分隔符表示消息可以发送到实例对
1、为什么压缩的原始数据一般采用YUV格式(1)利用人对图片感觉的生理特性,对于亮度信息比较敏感,对于色度信息不太敏感,所以视频编码是将Y分量和UV分量分开来编码,并且可以减少UV分量.2、视频压缩原理(1)空间冗余:图像相邻像素之间的相关性,比如一帧图片被划分成多个16x16的块之后,相邻的块之间有很多明显的相似性。(2)时间冗余:时间相差较近的两张图片变化较小。(3)视觉冗余:我们的眼睛对某些细节不太敏感,对图像中的高频信息的敏感度小于低频信息,可以去除一些高频信息。(4)编码冗余:一幅图片中不同像素出现的概率是不同的,对于出现次数较多的像素,用少的位数来编码,对于出现次数较少的像素,用多
Python程序运行原理Python是一种脚本语言,编辑完成的程序,也称源代码,可以直接运行。从计算机的角度看,Python程序的运行过程包含两个步骤:解释器将源代码翻译成字节码(即中间码),然后由虚拟机解释执行。Python程序文件的扩展名通常为.py。在执行时,首先由Python解释器将.py文件中的源代码翻译成中间码,这个中间码是一个扩展名为.pyc的文件,再由Python虚拟机(PythonVirtualMachine,PVM)逐条将中间码翻译成机器指令执行。需要说明的是,pyc文件保存在Python安装目录的pycache文件夹下,如果Python无法在用户的计算机上写人字节码,字节
我正在学习Rails数据库连接池概念。在Rails应用程序中,我将池大小定义为5。我对连接池大小的理解如下。当服务器启动时,rails会自动创建n个在database.yml文件中定义的连接。在我的例子中,它将创建5个连接,因为池大小为5。在每个http请求上,如果需要访问数据库,rails将使用连接池中的可用连接来处理请求。但我的问题是,如果我一次达到1000个请求,那么大部分请求将无法访问数据库连接,因为我的连接池大小只有5个。我上面对rails连接池的理解对吗??谢谢, 最佳答案 目的:数据库连接不是线程安全的;所以Activ