본문 바로가기
iOS/설명

[iOS] CFGetRetainCount

by Sky Titan 2022. 6. 2.
728x90
 

Apple Developer Documentation

 

developer.apple.com

CFGetRetainCount

  • Core Foundation Object의 reference count를 반환한다.
  • memory leak이 있는 부분을 디버깅할 때 사용하면 유용하다.

 

예제

class Test {
    
    deinit {
        print("deinit \(CFGetRetainCount(self))")
    }
    
    var closure: (() -> Void)? = {
    }
    
    func doing() {
        defer {
            print("doing defer \(CFGetRetainCount(self))")
        }
        print("doing start \(CFGetRetainCount(self))")
        closure = {
            self
        }
        
    }
}

var test: Test? = Test()
print("init \(CFGetRetainCount(test))")
test = nil

/*
init 2
deinit 2
*/
  •  인스턴스 생성 후 변수에 할당 후 출력하면 count가 2로 나온다.
    • 정확한 이유를 찾진 못했는데 아마 CFGetRetainCount안에 argument로 들어가면서 참조가 하나 더 생겨서 2로 출력되는 걸로 추측된다.
    • 따라서 deinit에서도 retain count는 2로 출력된다.

 

메모리 누수 디버깅하는 예제

class Test {
    
    deinit {
        print("deinit \(CFGetRetainCount(self))")
    }
    
    var closure: (() -> Void)? = {
    }
    
    func doing() {
        defer {
            print("doing defer \(CFGetRetainCount(self))")
        }
        print("doing start \(CFGetRetainCount(self))")
        closure = {
            self // weak self를 사용하지 않아, 강한 참조로 인해 count 1 증가
        }
        
    }
}

var test: Test? = Test()
print("init \(CFGetRetainCount(test))")
test?.doing()
print("before deinit \(CFGetRetainCount(test))")
test = nil //메모리 해제 시도

/*
init 2
doing start 3
doing defer 4
before deinit 3
*/

 closure 프로퍼티에서 강한 참조로 self를 물고 있어서 doing메서드를 실행할 때 참조가 1 증가해서 deinit시에 참조수가 기본값인 2가 남아야 해제가 되지만 참조 수가 3이므로 해제가 되지 않는다.

 

class Test {
    
    deinit {
        print("deinit \(CFGetRetainCount(self))")
    }
    
    var closure: (() -> Void)? = {
    }
    
    func doing() {
        defer {
            print("doing defer \(CFGetRetainCount(self))")
        }
        print("doing start \(CFGetRetainCount(self))")
        closure = { [weak self] in
            self // weak self를 사용하여 참조 증가 x
        }
        
    }
}

var test: Test? = Test()
print("init \(CFGetRetainCount(test))")
test?.doing()
print("before deinit \(CFGetRetainCount(test))")
test = nil // 메모리 해제 시도

/*
init 2
doing start 3
doing defer 3
before deinit 2
deinit 2
*/

 closure안에 weak self를 사용하자 정상적으로 메모리가 해제된다.

728x90

댓글