對(duì)于iOS開發(fā)恢口,OC語言前端使用Clang
編譯器咏瑟,swift
語言前端使用swift編譯器swiftc
饱溢,這兩個(gè)編譯器將我們寫的代碼編譯生成IR中間代碼
,后端都是通過LLVM進(jìn)行優(yōu)化窟她,接著交給代碼生成器生成機(jī)器語言
,最終形成.o機(jī)器執(zhí)行文件
蔼水。
在研究Swift之前震糖,先來探究一下Swift類結(jié)構(gòu)。
一趴腋、Swift類初始化
先寫一段簡(jiǎn)單的代碼:
class Person {
var age: Int = 33
var name: String = "chen"
}
let t = LGPerson()
生成SIL
(Swift intermediate language)命令:swiftc -emit-sil main.swift | xcrun swift-demangle >> ./main.sil && open main.sil
xcrun swift-demangle
用于還原變量吊说,下文未用。
class Person {
@_hasStorage @_hasInitialValue var age: Int { get set }
@_hasStorage @_hasInitialValue var name: String { get set }
@objc deinit
init()
}
@_hasStorage @_hasInitialValue let t: Person { get }
// t
sil_global hidden [let] @$s4main1tAA6PersonCvp : $Person
// main
sil @main : $@convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 {
bb0(%0 : $Int32, %1 : $UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>):
alloc_global @$s4main1tAA6PersonCvp // id: %2
%3 = global_addr @$s4main1tAA6PersonCvp : $*Person // user: %7
%4 = metatype $@thick Person.Type // user: %6
// function_ref Person.__allocating_init()
%5 = function_ref @$s4main6PersonCACycfC : $@convention(method) (@thick Person.Type) -> @owned Person // user: %6
%6 = apply %5(%4) : $@convention(method) (@thick Person.Type) -> @owned Person // user: %7
store %6 to %3 : $*Person // id: %7
%8 = integer_literal $Builtin.Int32, 0 // user: %9
%9 = struct $Int32 (%8 : $Builtin.Int32) // user: %10
return %9 : $Int32 // id: %10
} // end sil function 'main'
@main
標(biāo)識(shí)當(dāng)前swift文件的入口函數(shù)优炬,SIL標(biāo)識(shí)
符號(hào)名稱以@
作為前綴
颁井。%0
,%1
...在SIL中也叫寄存器
,類似代碼中的常量蠢护,一旦賦值后不可修改雅宾。如果SIL中還要繼續(xù)使用,就需要使用新的寄存器葵硕。
SIL代碼解讀:
alloc_global @$s4main1tAA6PersonCvp :
@$s4main1tAA6PersonCvp反混淆出來就是Person秀又,創(chuàng)建全局變量Person
%3 = global_addr @$s4main1tAA6PersonCvp : $*Person :讀取全局變量Person地址单寂,賦值給%3
%4 = metatype $@thick Person.Type :讀取Person的Type,賦值給%4
%5 = function_ref @$s4main6PersonCACycfC : $@convention(method) (@thick Person.Type) -> @owned Person : 定義一個(gè)function_ref即函數(shù)吐辙,就是%5宣决,這個(gè)函數(shù)入?yún)⑹荘erson.Type
%6 = apply %5(%4) : $@convention(method) (@thick Person.Type) -> @owned Person
:調(diào)用函數(shù)%5,入?yún)⒕褪?4昏苏,將返回結(jié)果賦給%6
store %6 to %3 : $*Person :將%6的結(jié)果存儲(chǔ)到%3尊沸,%3是LGPerson的地址
%8 = integer_literal $Builtin.Int32, 0 和 %9 = struct $Int32 (%8 : $Builtin.Int32)
:就是構(gòu)建一個(gè)Int值
return %9 : $Int32: 最終返回值
總結(jié)一下,main函數(shù)贤惯,通過Type
返回了一個(gè)全局變量Person
洼专。
實(shí)例化過程__allocating_init
// Person.__allocating_init()
sil hidden [exact_self_class] @$s4main6PersonCACycfC : $@convention(method) (@thick Person.Type) -> @owned Person {
// %0 "$metatype"
bb0(%0 : $@thick Person.Type):
%1 = alloc_ref $Person // user: %3
// function_ref Person.init()
%2 = function_ref @$s4main6PersonCACycfc : $@convention(method) (@owned Person) -> @owned Person // user: %3
%3 = apply %2(%1) : $@convention(method) (@owned Person) -> @owned Person // user: %4
return %3 : $Person // id: %4
} // end sil function '$s4main6PersonCACycfC'
代碼解讀
%1 = alloc_ref $Person :讀取Person的alloc_ref方法地址,給%1
%2 = function_ref @$s4main6PersonCACycfc : $@convention(method) (@owned Person) -> @owned Person : 讀取Person.init()函數(shù)地址孵构,給%2
%3 = apply %2(%1) : $@convention(method) (@owned Person) -> @owned Person // user: %4 : 調(diào)用alloc_ref創(chuàng)建一個(gè)Person實(shí)例對(duì)象屁商,給%3
return %3 : $Person :返回%3的實(shí)例對(duì)象
總結(jié)一下就是,調(diào)用alloc_ref
颈墅、init
方法蜡镶,返回對(duì)象。
init
方法主要用于初始化變量恤筛,和OC
中是一致的官还。這個(gè)過程用Swift代碼會(huì)更簡(jiǎn)潔:Person() == [[Perosn alloc] init]
。
初始化過程毒坛,在底層是怎么實(shí)現(xiàn)的望伦,通過__allocating_init
斷點(diǎn),我們可以跟進(jìn)去
swift實(shí)例對(duì)象的創(chuàng)建流程
__allocating_init
->swift_allocObject
->_swift_allocObject_
->swift_slowAlloc
->malloc_zone_malloc
具體實(shí)現(xiàn)煎殷,參考Swift源碼屯伞,最終對(duì)象會(huì)被轉(zhuǎn)為HeapObject
類型。
二豪直、Swift類的結(jié)構(gòu)
2.1 HeapObject結(jié)構(gòu)體
HeapObject
結(jié)構(gòu)體有兩個(gè)成員變量:元數(shù)據(jù)metadata 和 引用計(jì)數(shù)refCounts愕掏,總共16字節(jié)
。
2.2 metadata的解析
HeapMetedata
—> TargetHeapMetadata
—> TargetMetadata
顶伞,他們都是struct類型
饵撑,TargetMetadata
里面只有一個(gè)成員變量kind
。
通過注釋
和getKind()
找到如下代碼:
/// Get the metadata kind.
MetadataKind getKind() const {
return getEnumeratedMetadataKind(Kind);
}
/// Try to translate the 'isa' value of a type/heap metadata into a value
/// of the MetadataKind enum.
inline MetadataKind getEnumeratedMetadataKind(uint64_t kind) {
if (kind > LastEnumeratedMetadataKind)
return MetadataKind::Class;
return MetadataKind(kind);
}
getKind
是調(diào)用getEnumeratedMetadataKind
唆貌,而入?yún)?code>kind是uint64_t
類型滑潘,占8字節(jié)
大小,所以元數(shù)據(jù)metadata
是8字節(jié)
大小锨咙。
kind類型如下:
name | value |
---|---|
Class | 0x0 |
Struct | 0x200 |
Enum | 0x201 |
Optional | 0x202 |
ForeignClass | 0x203 |
Opaque | 0x300 |
Tuple | 0x301 |
Function | 0x302 |
Existential | 0x303 |
Metatype | 0x304 |
ObjCClassWrapper | 0x305 |
ExistentialMetatype | 0x306 |
HeapLocalVariable | 0x400 |
HeapGenericLocalVariable | 0x500 |
ErrorObject | 0x501 |
LastEnumerated | 0x7FF |
metadata的數(shù)據(jù)結(jié)構(gòu)體
:
struct swift_class_t: NSObject{
void *kind;//相當(dāng)于OC中的isa语卤,kind的實(shí)際類型是unsigned long。兼容oc,swift對(duì)象轉(zhuǎn)換為oc時(shí)粹舵,即為isa指針钮孵。
void *superClass;
void *cacheData;
void *data;
uint32_t flags; //4字節(jié)
uint32_t instanceAddressOffset;//4字節(jié)
uint32_t instanceSize;//4字節(jié)
uint16_t instanceAlignMask;//2字節(jié)
uint16_t reserved;//2字節(jié)
uint32_t classSize;//4字節(jié)
uint32_t classAddressOffset;//4字節(jié)
void *description;
...
}
2.3 refCounts
接著我們看看refCounts
,refCounts
是InlineRefCounts
類型眼滤,搜索InlineRefCounts
typedef RefCounts<InlineRefCountBits> InlineRefCounts;
InlineRefCounts
是RefCounts
類型
RefCounts
是class類型
巴席,確切的說,refCounts是個(gè)指針诅需,占8字節(jié)大小
漾唉。
綜上所述
swift類本質(zhì)是HeapObject
- HeapObject默認(rèn)大小為16字節(jié):
metadata(struct)8字節(jié)
和refCounts(class)8字節(jié)
所以,上文堰塌,Person的size應(yīng)該為40字節(jié) = age(Int)占8字節(jié) + name(String)占16字節(jié) + HeapObject(16字節(jié))
赵刑。
驗(yàn)證一下
class Person {
var age: Int = 33
var name: String = "chen"
}
let t = Person()
print("Int32 大小: \(MemoryLayout<Int32>.size)")
print("Int64 大小: \(MemoryLayout<Int64>.size)")
print("Int 大小: \(MemoryLayout<Int>.size)")
print("Srtring 大小: \(MemoryLayout<String>.size)")
print("Person 大小: \(class_getInstanceSize(Person.self))")
打印結(jié)果是: