Swiftでは、構造体(struct)、列挙型(enum)、タプル(tuple)などの値型は通常スタックに配置され、クラス(class)などの参照型はヒープに配置されます。
スタック割り当ては迅速で、自動であり、短いライフタイムのローカル変数を格納するために使用されます。ヒープ割り当ては追加のコストを伴い、ライフタイムやサイズが不明なオブジェクトのために使用されます。
例:
struct Point { var x: Int; var y: Int } let p1 = Point(x: 2, y: 3) // スタックに class Node { var value: Int; init(value: Int) { self.value = value } } let n1 = Node(value: 5) // ヒープに
注意点:
パフォーマンス: スタック割り当ては、ヒープのメモリ管理やオブジェクトのライフタイム管理が不要なため、より速いです。
すべての構造体(struct)は常にスタックに配置されますか?
回答:
いいえ!構造体は値型であり、通常はスタックに配置されますが、コンパイラはクラスのオブジェクト、配列、辞書の中に存在する場合にヒープに格納することがあります。たとえば:
class Box { var point: Point init(point: Point) { self.point = point } } let box = Box(point: Point(x: 1, y: 2))
ここでは、PointのインスタンスはBoxクラスに属するため、ヒープに保存されます。
ストーリー
開発者は、大きな構造体は常にスタック上にあると考え、パフォーマンスを最適化しようとしましたが、コレクション(Array、Dictionary)がヒープ割り当てを使用していることに気づかず、プロジェクトでのメモリ使用量の予期しない増加を引き起こしました。
ストーリー
プロジェクトでは、クロージャが構造体の値をキャプチャすることを考慮せず、ヒープに配置されるため、オブジェクトのライフタイムに影響を与えました。これにより変数のライフタイムが増え、自動解放が期待されていたため、メモリリークが発生しました。
ストーリー
重い構造体の配列を使用する際にコピーオンライトを理解していなかったため、スレッド間でコレクションを渡すことで予期しない高コストのコピー操作が発生し、パフォーマンスが低下し、UIでの遅延を引き起こしました。