0Pricing
Swift Academy · レッスン

MemoryLayoutとアライメント

型のサイズ、ストライド、アライメントを調べます。

「MemoryLayoutとアライメント」はCoddyKit上の無料Swift Academyレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはSwift Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Swift Academyコースには全4レッスンが含まれています。

メモリレイアウトが重要な理由

unsafe Swift を扱ったり C と橋渡ししたりする場合は、値がメモリ上にどのように配置されるかを知る必要があります。Swift の MemoryLayout<T> を使えば、生のバイト列に直接触れずにこれを調べられます。

これにより、値の大きさ、配列内で値同士がどれだけ離れているか、値がどのアドレス境界から始まる必要があるかという3つの疑問に答えられます。

// MemoryLayout works on any type
print(MemoryLayout<Int>.size)       // 8 on 64-bit
print(MemoryLayout<Bool>.size)      // 1
print(MemoryLayout<Double>.size)    // 8

size — 実際の格納領域

MemoryLayout<T>.size は、値の有効なデータが占めるバイト数です。配列内の要素間に置かれる可能性がある末尾のパディングは含みません。

単一の値が保持する意味のあるバイト数を知りたい場合は、size を使用します。

struct Point {
    var x: Int8   // 1 byte
    var y: Int64  // 8 bytes
}

print(MemoryLayout<Point>.size)   // 16 (not 9 — padding!)

stride — 配列内の間隔

stride は、値を連続配列に配置したときの、ある要素の先頭から次の要素の先頭までのバイト数です。size をアライメントに合わせて切り上げた値と等しくなります。

バッファーを手動で確保するときは、size ではなく必ず stride を掛けます。

print(MemoryLayout<Point>.stride) // 16
print(MemoryLayout<Int8>.stride)  // 1

// Buffer for 10 Points needs:
let bytes = 10 * MemoryLayout<Point>.stride // 160

alignment — アドレス境界

alignment は、値が開始しなければならないバイト境界です。アライメントが8の Int64 は、8で割り切れるアドレスから始める必要があります。コンパイラーはこれを満たすためにパディングを挿入します。

構造体のアライメントは、メンバーの中で最大のアライメントになります。

print(MemoryLayout<Int8>.alignment)   // 1
print(MemoryLayout<Int64>.alignment)  // 8
print(MemoryLayout<Point>.alignment)  // 8

size と stride の違い

多くの型では size == stride ですが、パディングがあると両者は異なります。次の要素を8バイト境界に揃える必要があるため、構造体の size が9であっても stride は16になる場合があります。

目安:単一の値について考えるときは size を、コレクションについて考えるときは stride を使います。

struct Mixed {
    var flag: Bool   // 1
    var value: Int   // 8
}
print(MemoryLayout<Mixed>.size)   // 16
print(MemoryLayout<Mixed>.stride) // 16

フィールドのオフセット

構造体では、キーパスを指定した MemoryLayout<T>.offset(of:) を使って、各保存プロパティが先頭からの相対位置のどこにあるかを確認できます。C 構造体に合わせてデータを配置するときに不可欠です。

struct Header {
    var magic: UInt32  // offset 0
    var length: UInt64 // offset 8 (padded)
}

print(MemoryLayout<Header>.offset(of: \Header.magic) ?? -1)  // 0
print(MemoryLayout<Header>.offset(of: \Header.length) ?? -1) // 8

空間を節約する並べ替え

アライメントのため、保存プロパティの順序はサイズに影響します。大きなフィールドを先に配置したり、サイズごとにまとめたりすると、構造体を小さくできます。無駄なバイトが積み重なる大きな配列では、特に重要です。

struct Wasteful { var a: Int8; var b: Int64; var c: Int8 } // size 24
struct Tight    { var b: Int64; var a: Int8; var c: Int8 } // size 16

print(MemoryLayout<Wasteful>.size)
print(MemoryLayout<Tight>.size)

参照型のレイアウト

クラスのインスタンスはヒープに割り当てられるため、クラス参照を保持する変数は単なる ポインターです。その MemoryLayout.size は、オブジェクトの大きさに関係なくポインターのサイズ(8バイト)になります。

構造体などの値型は内容をインラインで保持しますが、参照型が保持するのはポインターだけです。

class Big { var data = [Int](repeating: 0, count: 1000) }

print(MemoryLayout<Big>.size) // 8 — just the reference

オプショナルと列挙型

オプショナルは通常、タグのために1バイトを追加します。ただし Swift は参照型のオプショナルを最適化し、null ポインターを再利用するため、String? が String と同じサイズになる場合があります。

関連値を持つ列挙型は、最大のケースを格納できるサイズに識別情報の分を加えた大きさになります。

print(MemoryLayout<Int?>.size)    // 9
print(MemoryLayout<String>.size)  // 16
print(MemoryLayout<String?>.size) // 16 — no extra byte

インスタンスで of: を使う

size、stride、alignment の各メンバーには、インスタンスを基にした形式である MemoryLayout.size(ofValue:) もあります。型を明示しにくい場合や、型推論に任せる場合に便利です。

let tuple = (UInt8(1), UInt64(2))
print(MemoryLayout.size(ofValue: tuple))      // 16
print(MemoryLayout.stride(ofValue: tuple))    // 16
print(MemoryLayout.alignment(ofValue: tuple)) // 8

正しいレイアウトでの確保

生メモリを確保するときは、バイト数とアライメントの両方を渡す必要があります。これらを MemoryLayout から取得すれば、数値をハードコードするよりも、さまざまなアーキテクチャで正しく動作します。

let count = 4
let capacity = count * MemoryLayout<Int>.stride
let align = MemoryLayout<Int>.alignment

let raw = UnsafeMutableRawPointer.allocate(
    byteCount: capacity, alignment: align)
defer { raw.deallocate() }

確認問題

size と stride の違いについて理解できているか確認しましょう。

まとめ

メモリレイアウトの3つの基本要素を学びました:

  • size — 単一の値が持つ有効なバイト数
  • stride — 配列要素間の間隔(確保にはこちらを使用します)
  • alignment — 必要な開始境界

さらに、フィールド位置を調べる offset(of:)、プロパティの順序がサイズに与える影響、参照がポインターサイズにすぎないことも学びました。これらのツールを使えば、生メモリを安全に確保して解釈できます。

よくある質問

「MemoryLayoutとアライメント」レッスンは無料ですか?

はい。「MemoryLayoutとアライメント」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Swift Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Swift Academyコースには全4レッスンが含まれています。

「MemoryLayoutとアライメント」で何を学びますか?

型のサイズ、ストライド、アライメントを調べます。 ブラウザで直接実行するハンズオンコードでSwift Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Swift Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのSwift Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。

「MemoryLayoutとアライメント」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このSwift Academyレッスンでコードを書いて実行できますか?

はい。すべてのSwift Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. MemoryLayoutとアライメント
  2. UnsafePointerとUnsafeMutablePointer
  3. Unsafeバッファポインタ
  4. withUnsafeBytesとC相互運用
← Swift Academyに戻る