관리 메뉴

김종권의 iOS 앱 개발 알아가기

[iOS - swift] struct안에 있는 class 메모리 저장 위치 개념 (withUnsafePointer, MemoryLayout, Unmanaged, UnsafeRawPointer) 본문

iOS 응용 (swift)

[iOS - swift] struct안에 있는 class 메모리 저장 위치 개념 (withUnsafePointer, MemoryLayout, Unmanaged, UnsafeRawPointer)

jake-kim 2024. 7. 29. 01:36

struct, class 메모리 저장 위치

  • strucrt는 보통 메모리에서 stack영역에, class는 heap영역이 저장되는데, 아래처럼 struct안에 class 타입이 있을때 이것은 어디에 저장될 것인가?
class SomeClass {
    var value: Int
    init(value: Int) {
        self.value = value
    }
}

struct SomeStruct {
    var classInstance: SomeClass
    var otherValue: Int
}
  • 결론은 SomeStruct는 stack영역에 저장되고, SomeStruct의 class타입인 프로퍼티 classInstance는 heap영역에 저장됨

메모리 위치 알아내기

  • swift에서 heap과 stack영역의 메모리 주소를 어떻게 사용하는지 정확한 범위는 알 수 있지만 근사값 추측은 가능
  • value type 값을 만들어서 이 값을 pointer로 만든 다음 주소를 찍어보는 printStackAddress와 reference type을 하나 만들어서 주소를 찍어보는 함수 정의
func printStackAddress() {
    var stackVariable = 0
    withUnsafePointer(to: &stackVariable) { pointer in
        print("Stack memory address: \(pointer)")
    }
}

func printHeapAddress() {
    let heapVariable = UnsafeMutablePointer<Int>.allocate(capacity: 1)
    heapVariable.pointee = 0
    print("Heap memory address: \(heapVariable)")
    heapVariable.deallocate()
}

// Stack memory address: 0x000000016ef57570
// Heap memory address: 0x000060000318ca60
  • Stack보다 Heap의 주소가 더 큰 것을 확인
    • 이 값과 가까운 정도를 보고 heap에 저장되어 있는지 stack에 저장되어 있는지 아래에서 파악할 것
  • 메모리 주소를 알아낼 인스턴스 준비
let someClassInstance = SomeClass(value: 10)
let someStructInstance = SomeStruct(classInstance: someClassInstance, otherValue: 20)
  • class type을 품고 있는 struct 인스턴스의 저장 위치는 stack영역에 저장됨을 확인
withUnsafePointer(to: someStructInstance) { pointer in
    let startAddress = Int(bitPattern: pointer)
    let size = MemoryLayout.size(ofValue: someStructInstance)
    let endAddress = startAddress + size
    
    print("Struct instance memory start address: \(pointer)")
    print("Struct instance memory end address: \(UnsafeRawPointer(bitPattern: endAddress)!)")
    print("Struct memory size: \(size) bytes")
    print("Struct instance's class instance memory strat:", Unmanaged.passUnretained(someStructInstance.classInstance).toOpaque())
}

/*
Struct instance memory start address: 0x000000016d0b7850
Struct instance memory end address: 0x000000016d0b7860
Struct memory size: 16 bytes
Struct instance's class instance memory strat: 0x00006000015b2a80
*/
  • struct안에 있는 reference type은 heap 영역에 저장됨을 확인
let startAddress = Int(bitPattern: Unmanaged.passUnretained(someClassInstance).toOpaque())
let size = MemoryLayout<SomeClass>.size
let endAddress = startAddress + size

print("Class instance memory start address: \(Unmanaged.passUnretained(someClassInstance).toOpaque())")
print("Class instance memory end address: \(UnsafeRawPointer(bitPattern: endAddress)!)")
print("Class memory size: \(size) bytes")

/*
Class instance memory start address: 0x00006000015b2a80
Class instance memory end address: 0x00006000015b2a88
Class memory size: 8 bytes
*/

결론

  • struct와 class가 혼합되어 있을때, 둘 다 동일한 메모리 주소에 저장하지 않고 각 별도로 저장함
  • struct안에 class 타입이 있을 때, struct는 stack영역에 저장하고 struct안의 class 타입은 heap영역에 저장됨

* 전체 코드: https://github.com/JK0369/ExMemory_lab

Comments