web-dev-qa-db-ja.com

ヒープ上のオブジェクトのサイズ(バイト単位)を取得します

MemoryLayout<T>.sizeを使用してタイプTのサイズを取得できることは承知しています。

例:MemoryLayout<Int32>.size // 4

ただし、クラスインスタンス(オブジェクト)の場合、MemoryLayout<T>.sizeは、ヒープ上の実際のオブジェクトのサイズではなく、オブジェクトへの参照のサイズ(64ビットマシンでは8バイト)を返します。

class ClassA { // Objects should be at least 8 bytes
    let x: Int64 = 0
}

class ClassB  {// Objects should be at least 16 bytes
    let x: Int64 = 0
    let y: Int64 = 0
}

MemoryLayout<ClassA>.size // 8
MemoryLayout<ClassB>.size // 8, as well :(

オブジェクト自体のサイズを取得するにはどうすればよいですか?

不思議に思う人のために、私はこれを本当に必要としません。私はSwiftとCとの相互運用性について調べているだけです。

Appleプラットフォームの1つのオプション、なぜならSwiftクラスは 現在Objective-Cクラスの上に構築されている) そこには、Obj-Cランタイム関数を使用することになります class_getInstanceSize 、これは、パディングを含む、クラスのインスタンスのサイズをバイト単位で示します。

// on a 64-bit machine (1 Word == 8 bytes)...

import Foundation

class C {}
print(class_getInstanceSize(C.self)) // 16 bytes metadata for empty class 
                                     // (isa ptr + ref count)

class C1 {
    var i = 0
    var i1 = 0
    var b = false
}

print(class_getInstanceSize(C1.self)) // 40 bytes
// (16 metadata + 24 ivars, 8 for i + 8 for i1 + 1 for b + 7 padding)
11
Hamish

Playgroundでテストした限り、この関数は一見有意な値を返します。

func heapSize(_ obj: AnyObject) -> Int {
    return malloc_size(Unmanaged.passRetained(obj).toOpaque())
}

class MyClass {
    //no properites...
}
let myObj = MyClass()
print(heapSize(myObj)) //->16

class MyBiggerClass {
    var str: String?
    var i: Int = 0
}
let myBiggerObj = MyBiggerClass()
print(heapSize(myBiggerObj)) //->64

現在のSwiftランタイムはmalloc互換のものを使用して、ヒープにメモリを割り当てているようです。(mallocは、割り当てられたサイズを2の累乗に合わせるためのパディングを提供します。小さなチャンクを割り当てる場合。したがって、インスタンスに実際に必要なサイズは、malloc_sizeよりも小さい場合があります。)

私はこれがどこまで機能するかをテストしていません、そして現在の実装に依存する文書化されていない動作は通知なしで将来いつでも変更されるでしょう

しかし、実際にそれを知っているのであれば、これは探索の良い出発点になる可能性があります。

15
OOPer