CFGetRetainCount로 클래스의 참조 횟수 확인하기

지눙·2025년 3월 29일

Swift의 ARC(Automatic Reference Counting)

Swift는 메모리 관리를 위해 ARC를 사용합니다. ARC는 클래스의 인스턴스가 더 이상 필요하지 않을 때 자동으로 메모리에서 해제합니다.

ARC의 기본 원리는 다음과 같습니다:

  • 객체에 대한 강한 참조가 생성될 때마다 참조 카운트가 1 증가합니다.
  • 참조가 제거될 때마다 참조 카운트가 1 감소합니다.
  • 참조 카운트가 0이 되면 객체는 메모리에서 해제합니다.

CFGetRetainCount(_:)

https://developer.apple.com/documentation/corefoundation/1521288-cfgetretaincount

공식 문서에 따르면, ‘Core Foundation의 객체의 참조 횟수를 반환한다’고 합니다. 일반적으로 사용하지 않으나, 메모리 누수(Memory leak)를 디버깅할 때 유용하다고 하네요.

메서드의 인자로 받는 타입인 CFTypeRef는 무엇인가 살펴보니, AnyObject 였습니다. AnyObject는 Swift의 모든 클래스들이 따르는 프로토콜을 의미합니다.

코드로 CFGetRetainCount 사용해보기

import Foundation

class MyClass {
    var name: String
    
    init(name: String) {
        self.name = name
        print("\(name) 객체가 생성되었습니다.")
    }
    
    deinit {
        print("\(name) 객체가 해제되었습니다.")
    }
}

// 테스트 코드
func testRetainCount() {
    let obj1 = MyClass(name: "객체1")
    print("obj1 생성 후 \(CFGetRetainCount(obj1))")
    
    // 새로운 스코프에서 강한 참조 생성
    do {
        var obj2: MyClass? = obj1
        print("obj2 = obj1 할당 후 \(CFGetRetainCount(obj2))")
    }
    
    print("obj2 스코프 종료 후 \(CFGetRetainCount(obj1))")
    
    // 약한 참조 테스트
    weak var weakObj = obj1
    print("weak 참조 추가 후 \(CFGetRetainCount(obj1))")
}

testRetainCount()

/*
 객체1 객체가 생성되었습니다.
 obj1 생성 후: 참조 카운트 = 2
 obj2 = obj1 할당 후: 참조 카운트 = 3
 obj2 스코프 종료 후: 참조 카운트 = 2
 weak 참조 추가 후: 참조 카운트 = 2
 객체1 객체가 해제되었습니다.
 */

객체를 생성 했을 때 참조 횟수가 2인 것은 CFGetRetainCount를 호출하면, 참조 횟수를 위한 참조로 인해 참조 횟수가 1 증가하는 것으로 추측됩니다.

구조체는 어떨까요?

struct MyStruct {
   var name: String
   
   init(name: String) {
       self.name = name
       print("\(name) 객체가 생성되었습니다.")
   }
}

let obj = MyStruct(name: "구조체1")
print("구조체1 생성 후: 참조 카운트 \(CFGetRetainCount(obj))") // Argument type 'MyStruct' expected to be an instance of a class or class-constrained type

CFGetRetainCount의 인자는 CFTypeRef(=AnyObject) 타입 즉, 클래스 이어야 하기 때문에 컴파일 오류가 발생하게 됩니다.

0개의 댓글