Swift進(jìn)階-類與結(jié)構(gòu)體
Swift-函數(shù)派發(fā)
Swift進(jìn)階-屬性
Swift進(jìn)階-指針
Swift進(jìn)階-內(nèi)存管理
Swift進(jìn)階-TargetClassMetadata和TargetStructMetadata數(shù)據(jù)結(jié)構(gòu)源碼分析
Swift進(jìn)階-Mirror解析
Swift進(jìn)階-閉包
Swift進(jìn)階-協(xié)議
Swift進(jìn)階-泛型
Swift進(jìn)階-String源碼解析
Swift進(jìn)階-Array源碼解析
一努咐、源碼分析Array的內(nèi)存結(jié)構(gòu)
通過(guò)字面量初始化數(shù)組背后發(fā)生的事情测砂,通過(guò) SIL
來(lái)觀察一下數(shù)組:
var number = [1, 2, 3, 4, 5, 6]
當(dāng)我們通過(guò)字面量的方式創(chuàng)建一個(gè)Array
的時(shí)候就會(huì)調(diào)用_allocateUninitializedArray
箕戳;
在swift源碼中找到ArrayShared.swift
的 _allocateUninitializedArray
的聲明:
/// Returns an Array of `_count` uninitialized elements using the
/// given `storage`, and a pointer to uninitialized memory for the
/// first element.
///
/// This function is referenced by the compiler to allocate array literals.
///
/// - Precondition: `storage` is `_ContiguousArrayStorage`.
@inlinable // FIXME(inline-always)
@inline(__always)
@_semantics("array.uninitialized_intrinsic")
public // COMPILER_INTRINSIC
func _allocateUninitializedArray<Element>(_ builtinCount: Builtin.Word)
-> (Array<Element>, Builtin.RawPointer) {
// builtinCount元素個(gè)數(shù)
let count = Int(builtinCount)
if count > 0 {
// 如果大于0就創(chuàng)建內(nèi)存空間
// Doing the actual buffer allocation outside of the array.uninitialized
// semantics function enables stack propagation of the buffer.
// allocWithTailElems_1最終會(huì)調(diào)用allocObject來(lái)分配堆區(qū)內(nèi)存空間搏熄,來(lái)去存儲(chǔ)數(shù)組當(dāng)中的元素
let bufferObject = Builtin.allocWithTailElems_1(
getContiguousArrayStorageType(for: Element.self),
builtinCount, Element.self)
// _adoptStorage其實(shí)就是創(chuàng)建array
let (array, ptr) = Array<Element>._adoptStorage(bufferObject, count: count)
return (array, ptr._rawValue)
}
// 如果小于等于0就創(chuàng)建空類型的數(shù)組(字面量創(chuàng)建數(shù)組會(huì)走這種方式)
// For an empty array no buffer allocation is needed.
let (array, ptr) = Array<Element>._allocateUninitialized(count)
return (array, ptr._rawValue)
}
1.如果參數(shù)builtinCount
元素個(gè)數(shù)大于0秉溉,就創(chuàng)建內(nèi)存空間叛拷;
Builtin.allocWithTailElems_1
最終會(huì)調(diào)用alloc_Object
來(lái)分配堆區(qū)內(nèi)存空間应结,來(lái)去存儲(chǔ)數(shù)組當(dāng)中的元素堆生;
Array<Element>._adoptStorage
其實(shí)就是創(chuàng)建返回了array和第一個(gè)元素首地址匣沼。
2.如果參數(shù)builtinCount
元素個(gè)數(shù)小于等于0狰挡,就創(chuàng)建空類型的數(shù)組。
找到Array.swift
的_adoptStorage
的聲明:
/// Returns an Array of `count` uninitialized elements using the
/// given `storage`, and a pointer to uninitialized memory for the
/// first element.
///
/// - Precondition: `storage is _ContiguousArrayStorage`.
@inlinable
@_semantics("array.uninitialized")
internal static func _adoptStorage(
_ storage: __owned _ContiguousArrayStorage<Element>, count: Int
) -> (Array, UnsafeMutablePointer<Element>) {
let innerBuffer = _ContiguousArrayBuffer<Element>(
count: count,
storage: storage)
// 返回的是一個(gè)元組释涛,第一個(gè)元素是Array加叁,第二個(gè)元素是firstElement首地址
return (
Array(
_buffer: _Buffer(_buffer: innerBuffer, shiftedToStartIndex: 0)),
innerBuffer.firstElementAddress)
}
為什么還要返回第一個(gè)元素首地址呢?
是因?yàn)榈谝粋€(gè)元素前面還有是屬于Array
的內(nèi)存空間唇撬,告訴外界我這是首地址方便使用數(shù)據(jù)它匕。
Array
聲明的時(shí)候就知道_ContiguousArrayBuffer
是成員變量:
由于_ContiguousArrayBuffer
代碼比較多,我就不粘貼了窖认。
在ContiguousArrayBuffer.swift
找到_ContiguousArrayBuffer
的初始化函數(shù):
/// Initialize using the given uninitialized `storage`.
/// The storage is assumed to be uninitialized. The returned buffer has the
/// body part of the storage initialized, but not the elements.
///
/// - Warning: The result has uninitialized elements.
///
/// - Warning: storage may have been stack-allocated, so it's
/// crucial not to call, e.g., `malloc_size` on it.
@inlinable
internal init(count: Int, storage: _ContiguousArrayStorage<Element>) {
_storage = storage
_initStorageHeader(count: count, capacity: count)
}
發(fā)現(xiàn)_ContiguousArrayStorage
的實(shí)例_storage是_ContiguousArrayBuffer
的一個(gè)成員變量超凳。
于是我又找到ContiguousArrayBuffer.swift
里的_ContiguousArrayStorage
聲明:
// The class that implements the storage for a ContiguousArray<Element>
@_fixed_layout
@usableFromInline
internal final class _ContiguousArrayStorage<
Element
>: __ContiguousArrayStorageBase {
@inlinable
deinit {
_elementPointer.deinitialize(count: countAndCapacity.count)
_fixLifetime(self)
}
#if _runtime(_ObjC)
internal final override func withUnsafeBufferOfObjects<R>(
_ body: (UnsafeBufferPointer<AnyObject>) throws -> R
) rethrows -> R {
_internalInvariant(_isBridgedVerbatimToObjectiveC(Element.self))
let count = countAndCapacity.count
let elements = UnsafeRawPointer(_elementPointer)
.assumingMemoryBound(to: AnyObject.self)
defer { _fixLifetime(self) }
return try body(UnsafeBufferPointer(start: elements, count: count))
}
@objc(countByEnumeratingWithState:objects:count:)
@_effects(releasenone)
internal final override func countByEnumerating(
with state: UnsafeMutablePointer<_SwiftNSFastEnumerationState>,
objects: UnsafeMutablePointer<AnyObject>?, count: Int
) -> Int {
var enumerationState = state.pointee
if enumerationState.state != 0 {
return 0
}
return withUnsafeBufferOfObjects {
objects in
enumerationState.mutationsPtr = _fastEnumerationStorageMutationsPtr
enumerationState.itemsPtr =
AutoreleasingUnsafeMutablePointer(objects.baseAddress)
enumerationState.state = 1
state.pointee = enumerationState
return objects.count
}
}
@inline(__always)
@_effects(readonly)
@nonobjc private func _objectAt(_ index: Int) -> Unmanaged<AnyObject> {
return withUnsafeBufferOfObjects {
objects in
_precondition(
_isValidArraySubscript(index, count: objects.count),
"Array index out of range")
return Unmanaged.passUnretained(objects[index])
}
}
@objc(objectAtIndexedSubscript:)
@_effects(readonly)
final override internal func objectAtSubscript(_ index: Int) -> Unmanaged<AnyObject> {
return _objectAt(index)
}
@objc(objectAtIndex:)
@_effects(readonly)
final override internal func objectAt(_ index: Int) -> Unmanaged<AnyObject> {
return _objectAt(index)
}
@objc internal override final var count: Int {
@_effects(readonly) get {
return withUnsafeBufferOfObjects { $0.count }
}
}
@_effects(releasenone)
@objc internal override final func getObjects(
_ aBuffer: UnsafeMutablePointer<AnyObject>, range: _SwiftNSRange
) {
return withUnsafeBufferOfObjects {
objects in
_precondition(
_isValidArrayIndex(range.location, count: objects.count),
"Array index out of range")
_precondition(
_isValidArrayIndex(
range.location + range.length, count: objects.count),
"Array index out of range")
if objects.isEmpty { return }
// These objects are "returned" at +0, so treat them as pointer values to
// avoid retains. Copy bytes via a raw pointer to circumvent reference
// counting while correctly aliasing with all other pointer types.
UnsafeMutableRawPointer(aBuffer).copyMemory(
from: objects.baseAddress! + range.location,
byteCount: range.length * MemoryLayout<AnyObject>.stride)
}
}
/// If the `Element` is bridged verbatim, invoke `body` on an
/// `UnsafeBufferPointer` to the elements and return the result.
/// Otherwise, return `nil`.
internal final override func _withVerbatimBridgedUnsafeBuffer<R>(
_ body: (UnsafeBufferPointer<AnyObject>) throws -> R
) rethrows -> R? {
var result: R?
try self._withVerbatimBridgedUnsafeBufferImpl {
result = try body($0)
}
return result
}
/// If `Element` is bridged verbatim, invoke `body` on an
/// `UnsafeBufferPointer` to the elements.
internal final func _withVerbatimBridgedUnsafeBufferImpl(
_ body: (UnsafeBufferPointer<AnyObject>) throws -> Void
) rethrows {
if _isBridgedVerbatimToObjectiveC(Element.self) {
let count = countAndCapacity.count
let elements = UnsafeRawPointer(_elementPointer)
.assumingMemoryBound(to: AnyObject.self)
defer { _fixLifetime(self) }
try body(UnsafeBufferPointer(start: elements, count: count))
}
}
/// Bridge array elements and return a new buffer that owns them.
///
/// - Precondition: `Element` is bridged non-verbatim.
override internal func _getNonVerbatimBridgingBuffer() -> _BridgingBuffer {
_internalInvariant(
!_isBridgedVerbatimToObjectiveC(Element.self),
"Verbatim bridging should be handled separately")
let count = countAndCapacity.count
let result = _BridgingBuffer(count)
let resultPtr = result.baseAddress
let p = _elementPointer
for i in 0..<count {
(resultPtr + i).initialize(to: _bridgeAnythingToObjectiveC(p[i]))
}
_fixLifetime(self)
return result
}
#endif
/// Returns `true` if the `proposedElementType` is `Element` or a subclass of
/// `Element`. We can't store anything else without violating type
/// safety; for example, the destructor has static knowledge that
/// all of the elements can be destroyed as `Element`.
@inlinable
internal override func canStoreElements(
ofDynamicType proposedElementType: Any.Type
) -> Bool {
#if _runtime(_ObjC)
return proposedElementType is Element.Type
#else
// FIXME: Dynamic casts don't currently work without objc.
// rdar://problem/18801510
return false
#endif
}
/// A type that every element in the array is.
@inlinable
internal override var staticElementType: Any.Type {
return Element.self
}
@inlinable
internal final var _elementPointer: UnsafeMutablePointer<Element> {
return UnsafeMutablePointer(Builtin.projectTailElems(self, Element.self))
}
}
_ContiguousArrayStorage
是繼承自__ContiguousArrayStorageBase
的,最終在SwiftNativeNSArray.swift
找到了__ContiguousArrayStorageBase
的聲明:
/// Base class of the heap buffer backing arrays.
///
/// NOTE: older runtimes called this _ContiguousArrayStorageBase. The
/// two must coexist, so it was renamed. The old name must not be used
/// in the new runtime.
@usableFromInline
@_fixed_layout
internal class __ContiguousArrayStorageBase
: __SwiftNativeNSArrayWithContiguousStorage {
@usableFromInline
final var countAndCapacity: _ArrayBody
@inlinable
@nonobjc
internal init(_doNotCallMeBase: ()) {
_internalInvariantFailure("creating instance of __ContiguousArrayStorageBase")
}
#if _runtime(_ObjC)
internal override func withUnsafeBufferOfObjects<R>(
_ body: (UnsafeBufferPointer<AnyObject>) throws -> R
) rethrows -> R {
if let result = try _withVerbatimBridgedUnsafeBuffer(body) {
return result
}
_internalInvariantFailure(
"Can't use a buffer of non-verbatim-bridged elements as an NSArray")
}
/// If the stored type is bridged verbatim, invoke `body` on an
/// `UnsafeBufferPointer` to the elements and return the result.
/// Otherwise, return `nil`.
internal func _withVerbatimBridgedUnsafeBuffer<R>(
_ body: (UnsafeBufferPointer<AnyObject>) throws -> R
) rethrows -> R? {
_internalInvariantFailure(
"Concrete subclasses must implement _withVerbatimBridgedUnsafeBuffer")
}
internal func _getNonVerbatimBridgingBuffer() -> _BridgingBuffer {
_internalInvariantFailure(
"Concrete subclasses must implement _getNonVerbatimBridgingBuffer")
}
@objc(mutableCopyWithZone:)
dynamic internal func mutableCopy(with _: _SwiftNSZone?) -> AnyObject {
let arr = Array<AnyObject>(_ContiguousArrayBuffer(self))
return _SwiftNSMutableArray(arr)
}
@objc(indexOfObjectIdenticalTo:)
dynamic internal func index(ofObjectIdenticalTo object: AnyObject) -> Int {
let arr = Array<AnyObject>(_ContiguousArrayBuffer(self))
return arr.firstIndex { $0 === object } ?? NSNotFound
}
#endif
@inlinable
internal func canStoreElements(ofDynamicType _: Any.Type) -> Bool {
_internalInvariantFailure(
"Concrete subclasses must implement canStoreElements(ofDynamicType:)")
}
/// A type that every element in the array is.
@inlinable
internal var staticElementType: Any.Type {
_internalInvariantFailure(
"Concrete subclasses must implement staticElementType")
}
@inlinable
deinit {
_internalInvariant(
self !== _emptyArrayStorage, "Deallocating empty array storage?!")
}
}
整理得出:
struct Array
擁有 struct _ContiguousArrayBuffer
這個(gè)類型的成員耀态;
struct _ContiguousArrayBuffer
擁有 class _ContiguousArrayStorage
這個(gè)類型的成員轮傍;
class _ContiguousArrayStorage
繼承自class __ContiguousArrayStorageBase
這個(gè)類。
所以對(duì)于Array
內(nèi)存結(jié)構(gòu)可以分析如同下圖:
二首装、LLDB調(diào)試Array內(nèi)存結(jié)構(gòu)
Array
表現(xiàn)起來(lái)像是值類型创夜,因?yàn)?code>Array它是struct,而在lldb調(diào)試的時(shí)候編譯器幫我們處理仙逻,直接從第一個(gè)元素地址逐個(gè)做偏移取地址上的值驰吓。
number這個(gè)地址上對(duì)堆區(qū)地址的引用,通過(guò)x/8g格式化輸出:
本質(zhì)上Array
是一個(gè)引用類型系奉,只是在struct
上嵌套了一個(gè)class
檬贰;
又因?yàn)?code>Array是struct
所以在賦值的時(shí)候就會(huì)有一個(gè)寫時(shí)復(fù)制
的特性。
三缺亮、Array擴(kuò)容
var number = [1, 2, 3, 4, 5, 6]
number.append(100)
找到源碼里Array.swift
的append函數(shù)聲明:
/// Adds a new element at the end of the array.
///
/// Use this method to append a single element to the end of a mutable array.
///
/// var numbers = [1, 2, 3, 4, 5]
/// numbers.append(100)
/// print(numbers)
/// // Prints "[1, 2, 3, 4, 5, 100]"
///
/// Because arrays increase their allocated capacity using an exponential
/// strategy, appending a single element to an array is an O(1) operation
/// when averaged over many calls to the `append(_:)` method. When an array
/// has additional capacity and is not sharing its storage with another
/// instance, appending an element is O(1). When an array needs to
/// reallocate storage before appending or its storage is shared with
/// another copy, appending is O(*n*), where *n* is the length of the array.
///
/// - Parameter newElement: The element to append to the array.
///
/// - Complexity: O(1) on average, over many calls to `append(_:)` on the
/// same array.
@inlinable
@_semantics("array.append_element")
public mutating func append(_ newElement: __owned Element) {
// Separating uniqueness check and capacity check allows hoisting the
// uniqueness check out of a loop.
_makeUniqueAndReserveCapacityIfNotUnique()
let oldCount = _buffer.mutableCount
_reserveCapacityAssumingUniqueBuffer(oldCount: oldCount)
_appendElementAssumeUniqueAndCapacity(oldCount, newElement: newElement)
_endMutation()
}
_makeUniqueAndReserveCapacityIfNotUnique
相當(dāng)于是創(chuàng)建新的buffer內(nèi)存空間
_buffer.beginCOWMutation
的判斷邏輯
/// Returns `true` and puts the buffer in a mutable state if the buffer's
/// storage is uniquely-referenced; otherwise performs no action and
/// returns `false`.
///
/// - Precondition: The buffer must be immutable.
///
/// - Warning: It's a requirement to call `beginCOWMutation` before the buffer
/// is mutated.
@_alwaysEmitIntoClient
internal mutating func beginCOWMutation() -> Bool {
let isUnique: Bool
if !_isClassOrObjCExistential(Element.self) {
isUnique = _storage.beginCOWMutationUnflaggedNative()
} else if !_storage.beginCOWMutationNative() {
return false
} else {
isUnique = _isNative
}
#if INTERNAL_CHECKS_ENABLED && COW_CHECKS_ENABLED
if isUnique {
_native.isImmutable = false
}
#endif
return isUnique
}
其實(shí)數(shù)組擴(kuò)容是以2倍的方式
來(lái)看看是怎么擴(kuò)容的:
/// Creates a new buffer, replacing the current buffer.
///
/// If `bufferIsUnique` is true, the buffer is assumed to be uniquely
/// referenced by this array and the elements are moved - instead of copied -
/// to the new buffer.
/// The `minimumCapacity` is the lower bound for the new capacity.
/// If `growForAppend` is true, the new capacity is calculated using
/// `_growArrayCapacity`, but at least kept at `minimumCapacity`.
@_alwaysEmitIntoClient
internal mutating func _createNewBuffer(
bufferIsUnique: Bool, minimumCapacity: Int, growForAppend: Bool
) {
_internalInvariant(!bufferIsUnique || _buffer.isUniquelyReferenced())
_buffer = _buffer._consumeAndCreateNew(bufferIsUnique: bufferIsUnique,
minimumCapacity: minimumCapacity,
growForAppend: growForAppend)
}
_buffer._consumeAndCreateNew
找到ArrayBuffer.swift
的_consumeAndCreateNew函數(shù):
/// Creates and returns a new uniquely referenced buffer which is a copy of
/// this buffer.
///
/// This buffer is consumed, i.e. it's released.
@_alwaysEmitIntoClient
@inline(never)
@_semantics("optimize.sil.specialize.owned2guarantee.never")
internal __consuming func _consumeAndCreateNew() -> _ArrayBuffer {
return _consumeAndCreateNew(bufferIsUnique: false,
minimumCapacity: count,
growForAppend: false)
}
/// Creates and returns a new uniquely referenced buffer which is a copy of
/// this buffer.
///
/// If `bufferIsUnique` is true, the buffer is assumed to be uniquely
/// referenced and the elements are moved - instead of copied - to the new
/// buffer.
/// The `minimumCapacity` is the lower bound for the new capacity.
/// If `growForAppend` is true, the new capacity is calculated using
/// `_growArrayCapacity`, but at least kept at `minimumCapacity`.
///
/// This buffer is consumed, i.e. it's released.
@_alwaysEmitIntoClient
@inline(never)
@_semantics("optimize.sil.specialize.owned2guarantee.never")
internal __consuming func _consumeAndCreateNew(
bufferIsUnique: Bool, minimumCapacity: Int, growForAppend: Bool
) -> _ArrayBuffer {
let newCapacity = _growArrayCapacity(oldCapacity: capacity,
minimumCapacity: minimumCapacity,
growForAppend: growForAppend)
let c = count
_internalInvariant(newCapacity >= c)
let newBuffer = _ContiguousArrayBuffer<Element>(
_uninitializedCount: c, minimumCapacity: newCapacity)
if bufferIsUnique {
// As an optimization, if the original buffer is unique, we can just move
// the elements instead of copying.
let dest = newBuffer.firstElementAddress
dest.moveInitialize(from: mutableFirstElementAddress,
count: c)
_native.mutableCount = 0
} else {
_copyContents(
subRange: 0..<c,
initializing: newBuffer.mutableFirstElementAddress)
}
return _ArrayBuffer(_buffer: newBuffer, shiftedToStartIndex: 0)
}
_growArrayCapacity
函數(shù)就是擴(kuò)容相關(guān)代碼翁涤。
找到ArrayShared.swift
的_growArrayCapacity
函數(shù):
@inlinable
internal func _growArrayCapacity(_ capacity: Int) -> Int {
return capacity * 2
}
擴(kuò)容的判斷條件
@_alwaysEmitIntoClient
internal func _growArrayCapacity(
oldCapacity: Int, minimumCapacity: Int, growForAppend: Bool
) -> Int {
if growForAppend {
if oldCapacity < minimumCapacity {
// When appending to an array, grow exponentially.
return Swift.max(minimumCapacity, _growArrayCapacity(oldCapacity))
}
return oldCapacity
}
// If not for append, just use the specified capacity, ignoring oldCapacity.
// This means that we "shrink" the buffer in case minimumCapacity is less
// than oldCapacity.
return minimumCapacity
}
如果是count > capacity 則需要擴(kuò)容,每次擴(kuò)容都是以當(dāng)前的 capacity * 2的方式。
_reserveCapacityAssumingUniqueBuffer
如果數(shù)組是空的葵礼,_makeMutableAndUnique
不會(huì)將空的數(shù)組緩沖區(qū)替換為唯一的緩沖區(qū)(它只是將其替換為空的數(shù)組singleton)号阿。這個(gè)特定的情況是可以的,因?yàn)槲覀儗⑹咕彌_區(qū)在這個(gè)函數(shù)中是唯一的鸳粉,因?yàn)槲覀冋?qǐng)求的容量是> 0扔涧,因此_copyToNewBuffer
將被調(diào)用來(lái)創(chuàng)建一個(gè)新的緩沖區(qū)。
@inlinable
@_semantics("array.mutate_unknown")
internal mutating func _reserveCapacityAssumingUniqueBuffer(oldCount: Int) {
// Due to make_mutable hoisting the situation can arise where we hoist
// _makeMutableAndUnique out of loop and use it to replace
// _makeUniqueAndReserveCapacityIfNotUnique that precedes this call. If the
// array was empty _makeMutableAndUnique does not replace the empty array
// buffer by a unique buffer (it just replaces it by the empty array
// singleton).
// This specific case is okay because we will make the buffer unique in this
// function because we request a capacity > 0 and therefore _copyToNewBuffer
// will be called creating a new buffer.
let capacity = _buffer.mutableCapacity
_internalInvariant(capacity == 0 || _buffer.isMutableAndUniquelyReferenced())
if _slowPath(oldCount &+ 1 > capacity) {
_createNewBuffer(bufferIsUnique: capacity > 0,
minimumCapacity: oldCount &+ 1,
growForAppend: true)
}
}
_appendElementAssumeUniqueAndCapacity
附加元素假定唯一和容量
@inlinable
@_semantics("array.mutate_unknown")
internal mutating func _appendElementAssumeUniqueAndCapacity(
_ oldCount: Int,
newElement: __owned Element
) {
_internalInvariant(_buffer.isMutableAndUniquelyReferenced())
_internalInvariant(_buffer.mutableCapacity >= _buffer.mutableCount &+ 1)
_buffer.mutableCount = oldCount &+ 1
(_buffer.mutableFirstElementAddress + oldCount).initialize(to: newElement)
}