欢迎光临散文网 会员登陆 & 注册

研究笔记

2022-09-21 19:38 作者:スレーブ_スレイヤー  | 我要投稿

前两天我一直有一个疑问:一个复杂的类在编译以后,以什么样的形态存在于内存。

我的设想是,所有字段按顺序排列,然后是每个函数的地址按顺序排列。

现在看极度无厘头的想法,当时却深信不疑,想了想原因也很简单:

按照面向对象的思想,字段和函数必定放在一起。


结论就是,面向对象的思想只适用于编码阶段,在运行时类的函数和字段没有任何联系。类只是对内存的抽象,是由人类创造出的概念,计算机内部的运行是没有这个概念的。


于是结论1:在运行时(或者说编译以后),一个类的字段和函数没有任何联系。

疑问:怎么保证函数的正确调用?第一个参数传this指针就行了。调用方怎么知道this指针的地址?编译器会确保调用方知道。Why?object->fun();类似的句式,意味着调用方一定持有this指针,编译器做的只是把这个指针加到了第一个参数。


由此衍生出了一个新的问题,泛型类的函数调用又是怎么样的?写了几个例子反汇编以后,结论也很单纯,编译器会在最后添加一个参数传入泛型对象的大小。但还有一个问题,程序怎么知道对象具体的类型呢?例如两个int和一个INT64都是8字节。

我在官方STL的函数里没看到处理这些的代码,这些信息最终是怎么存储的依旧是未知。


但这不重要,我真正关心的是il2cpp编译方式下,泛型的处理。

上面的结论都是基于C++的vector,C#的List又是什么情况?

结论也很单纯甚至有点捞:il2cpp编译器会为每一个泛型类型的函数调用单独生成一份汇编代码。听起来很捞,几乎一样的逻辑生成了可能有几百几千份代码,但它就是这么做的。

当然,我还发现了几个比较诡异的地方,我一直认为STL存储的是对象的引用(地址),但是无论是vector还是List,它存储的都是对象里的值。JAVA表示完全无法理解。

当然两者都是可行的,并且是可以指定的,但是Java就不行,不存在在一个List里存储对象的值,只能存引用,如果存了多个相同的引用,改变其中一个其它的也会跟着改变。


结论2:il2cpp编译下的C#泛型函数,如果指定的类型是引用,那么遵循同一套逻辑;如果不是,那么单独为这个函数生成一份汇编代码。

差不多就是这样吧,Java用久了真的有些思维惯性,忽略了一些明明知道的,底层的东西。

研究笔记的评论 (共 条)

分享到微博请遵守国家法律