Hardtack's Blog

그냥 내 생각들...

Jan 4

Objective-C의 메모리관리

가끔 인터넷을 통해 iOS 관련 소스들을 참고하면 메모리 관리가 엉망인 경우가 자주 보인다.

개인적으로 답답해서 Objective-C의 메모리 관리가 어떻게 되는지, 어떤식으로 프로그래밍 해야 제대로 메모리 관리를 한 것인지 간략하게 적어보려고 한다. 본인도 틀린부분이 있을 수 있으니 피드백은 환영입니다.

가장먼저 Objective-C(이하 줄여서 ojbc로 하겠다)의 메모리 관리의 가장 중요한 개념인 retain count의 개념이다.

objc의 객체는 allocation(alloc method를 호출할때) 될때 retain count가 1이 되고 이 숫자가 0이 될 때 객체가 메모리에서 해제된다. 이 숫자는 10이 될 수도 100이 될 수도 있지만 0이 되야만 객체가 메모리에서 해제가 된다.

반대로 release method를 호출하면 retain count는 하나가 줄게된다.

예를 들면

NSObject* obj = [NSObject alloc]; -> retain count 1 상승

[obj release]; -> retain count 0 -> 메모리에서 해제

이렇게 된다.

우리는 이 retain count 개념을 통해 간단하게 메모리 관리를 할 수 있다.

두번째로 autorelease이다

흔히 objc에서 객체를 생성할때 두가지 방법을 사용한다.

첫번째로

NSString* str = [[NSString alloc] initWithString:@”string”];

이런식으로 allocation 후 initialize 해주는 방법

두번째로

NSString* str = [NSString stringWithString:@”string”];

이런식으로 간단하게 객체를 생성하는 방법(From C++ to Objective-C 에서는 Convinience constructor라고 부르더라)이 있다.

아마 stringWithString: method는 이렇게 구현되어있을것이다.

+(id)stringWithString:(NSString*)string{

id obj = [[self class] initWithString:string]; // [self class]는 자기 자신의 클래스를 자동으로 return해준다.

return [obj autorelease];

마지막 return문을 보면 autorelease라는 method를 호출한 것을 볼 수 있다. autorelease는 retain count를 1 감소시키지만 실제로는 감소되지 않은것으로 취급한다. 그렇다면 도대체 언제 감소되는 것인가? 정답은 NSAutoreleasePool에 있다. autorelease method를 호출하면 그 객체는 현재 생성되어있는 pool에 등록되게 되고 그 pool이 release 되는 순간 “정말로” retain count가 감소되게 된다. 그래서 모든 objc 어플리케이션에는(정확히는 모든 Thread마다 하나씩) NSAutoreleasePool이 있어야한다. 여러분의 iOS 프로젝트의 main.m에도 NSAutoreleasePool이 있을 것이다.

그렇다면 이 NSAutoreleasePool은 어떻게 활용되야 하는가? 다시 위의 예제를 보면 객체를 생성하고 pool에 등록한 후 return하는것을 볼 수 있다. 이렇게 함으로써 자신이 생성한 객체의 메모리 누수를 막을 수 있게된다. 그래서 objc에서 자신이 allocation한 객체를 return할 때에는 반드시 pool에 등록을 해야한다. 이것은 하나의 약속이다.(initializer가 init으로 시작하는것과 마찬가지이다)

그렇다면 이 객체를 받은 프로그래머는 그냥 이놈을 써도 좋은가? 그것은 아니다. pool에 등록된 객체는 언제 해제될지 모르는 시한폭탄과도 같은 존재이다. pool은 Thread마다 있는 존재이므로 multi Thread인 경우에는 더더욱 위험하다. 그래서  Convinience constructor를 통해 생성한 객체를 생성한 method가 아닌 다른 method에서 사용할 경우에는 반드시 retain method를 호출 해주어야한다. 간단하게 예를 들어보자

다음과 같은 클래스가 있다.

@interface ExClass : NSObject{

NSString* str;

@end

@implementation ExClass

- (void)mkStr{

NSStirng* tmp = [NSString stringWithString:@”asd”]; // tmp 객체는 이 method내에서만 사용되므로 다른 pool과 연관이 될 염려가 없다. 그러므로  retain을 하지 않아도 된다.

str = [[NSString stringWithFormat:@”%@%@”, tmp,@”123”] retain]; // str 객체는 클래스 “ExClass”의 멤버이기 때문에 다른 pool과 연관될 가능성이 있다. 그러므로 retain을 해서 안전하게 보관해야 한다.

@end

다른 pool과 연관되는것이 상상이 되지 않는 분들을 위해 간단한 예를 들어 보겠다.

str 객체에 웹에 있는 게시글의 제목을 저장한다고 하자 네트워크 연동이므로 당연히 Multi Thread를 사용할 것이다 네트워크 관련 Thread를 B라고 하면 B는 자신의 pool을 가지고 있을것이고 B의 thread 에서 Convinience constructor를 통해 생성된 객체 str은 B의 pool에 등록이 될것이다. 네트워크 작업이 끝나고 B의 pool도 release된다면 str의 retain count는 감소할 것이며 retain을 호출 하지 않았다면 메모리에서 해제될 것이다. 그리고 UI관련 Thread인 A에서 str을 화면에 띄우려고 하면 str은 이미 B의 pool이 release되면서 메모리에서 해제가 되어있을것이다. 이러한 상황을 방지하기 위해서는 반드시 retain을 호출 해주어야 한다.

다음은 property이다. 이곳에서는 property의 최소한만 소개할 것이다.

자주 값이 변경되는 멤버는 변경되기전에 자신이 retain했던 객체를 release해주어야 할것이다.

예를 들어보자(mInstance는 클래스의 멤버이고 instance는 멤버에 대입될 객체이다.)

if (mInstance != nil){ // mInstance에 값이 이미 있으면

[mInstance release]; // release하고

}

mInstance = [instance retain]; // retain해서 새로운 값을 안전하게 보관한다.

값을 대입할때마다 일일히 저런식으로 하는것은 매우 번거롭다. 그래서 setter를 구현해서 관리를 하게된다. setter의 예를 들어보겠다.

- (void)setMInstance:(id)instance{

if (mInstance != nil){

[mInstance release];

}

mInstance = [instance retain];

이런식으로 구현해 놓으면 필요할때마다 setter만 호출해서 대입하면 되기 때문에 메모리도 편하고 안전하게 관리할 수 있다. 그런데! 이것마저도 멤버의 수가 많아지면 소스의 길이가 길어져 복잡해지기 마련이다. 그래서 objc2.0에서 새로 나온것이(다른 많은 언어에는 이미 있었지만) property이다. 일단 책이나 예제에서 많이 본 property의 예를 보자

@property (nonatomic, retain) id instance;

그리고 .m 파일에서

@implementation …

@synthesize instance;

먼저 property는 instance라는 getter와 setInstance:라는 setter를 생성해준다.(원한다면 getter, setter의 이름을 바꿀수도, property와 실제 멤버의 이름을 다르게 할수도 있지만 지금은 다루지 않겠다.)

그리고 (nonatomic, retain)은 property의 getter, setter 옵션이다. nonatomic(Non-Atomic)은 멀티 Thread에서의 안전을 보장하지 않는다는 뜻이다. 그리고 retain은 setter를 통해 값이 바뀔때마다 전의 값을 release하고 새로운 값을retain을 해주겠다는 뜻이다. 위의 setMInstance: 와 똑같이

이런식으로 getter, setter를 구현하거나 property를 만들면 그 객체의 메모리 관리는 크게 신경 안써도 되지만 꼭 release를 해야하는 곳이 있다. 바로 dealloc 이다. dealloc에서는 반드시 수동으로 모든 멤버를 release해주어야 한다. 또 iOS의 경우에는 ViewController에서 viewDidUnload에서 멤버를 해제하거나 프로퍼티에 nil을 대입합으로써 view와 관련된 멤버를 해제해야한다.

이상 본인이 알고있는 objc의 메모리 관리에 대해서 적어보았다. 위의 내용을 잘 숙지하고 Xcode의 “Build and Analyze”기능을 잘 사용한다면 메모리 leak없는 objc 프로그래밍을 할 수 있을것이다.

피드백은 환영!


Dec 9

주변에 ‘취미로만’ 프로그래밍을 하는 사람이 생각보다 많은 것 같다. 그들은 프로그래밍을 무엇으로 생각할까?


Dec 1

더 높은 곳에 오르지 못했다. 그래도 후회는 없다.

프로그래밍을 시작한게 고1이었던 작년, 실전개발을 시작한건 올해 초, 나에게 지난 4개월의 기회는 너무나도 컸다.

하지만 그 기회를 완전히 잡기엔 나는 너무나도 작았다.

하지만 그 기회는 나를 성장 시켜주었고 평생 이런 좋은 기회는 다시 오지 않을 것 같다.

비록 기회는 놓쳤지만 나의 성장은 무엇으로도 보답할 수 없을 것이다.

다른사람에게 프로그래밍을 배워본적도 없고 당시 경력이 프로그래밍 1년 반 이었던 나에게 이런 과분한 기회를 준 멘토분들께 깊이 감사하고있다.

지금 하는 공모전이 끝나면 1년동안 나를 더 큰사람을 만들어 줄 수 있는 대학을 향해 가는것에 전념할 것이다.

나중에 같이 했던 분들 보기 부끄럽지않기위해서, 또 이런 기회를 다른사람에게도 나누어 줄 수 있는 사람이 되기 위해서


Nov 28

오늘 면접에서 ‘내가 만들어보고 싶은 것’을 물어봤다. 내가 만들어보고 싶은 것 솔직히 없다. 내 생각을 ‘수학’에 비유하자면 수학을 좋아해서 수학을 하는, 즉 학술적 연구로서의 수학을 하는 사람의 마음이랄까? 지금의 나는 단순히 컴퓨터가 좋아서 프로그래밍을 하는 것이다. 이런 마인드에서 ‘내가 만들어보고 싶은 것’을 물어보니 아까는 만족스러운 대답이 나오지 못한 것 같다.

결론 나는 프로그래밍을 더 ‘연구’하고 싶다.


Nov 25

오랜만에 안드로이드 개발을(어쩔수없이) 했다. 유난히 안드로이드 개발할때만 멈추는 이클립스에 부팅하는데 3박4일 걸리는 시뮬레이터… 안드로이드 발전의 발목을 잡는 한 면을 느꼈다. 솔직히 이건 윈도우모바일 개발환경이 부러울 지경이다


Nov 18

Java에 대해서

최근 좋은 기회가 생겨 소프트웨어 관련해서 많은 것을 배울 수 있는 활동을 하고있는데 이번 프로젝트는 Java를 사용하여 진행이 되고있다.

솔직히 그전까지는 Java에 대해서 꽤나 부정적인 입장이었다. 그런데 이번 프로젝트의 멘토분께서 Java에 대한 재미있는 특징들을 보여주셔서 Java에 감탄하기도 하고 긍정적으로 보게되었다.

Java로 프로젝트를 진행하면서 “Java 괜찮은데? 그래도 Java로 벌어먹고 싶지는 않다” 라는 생각이 자주 들었다.

나의 생각에서 두번째 문장 “그래도 Java로 벌어먹고 싶지는 않다” 나 자신도 어떤이유인지 모르는 찝찝한 기분이들었다. 그래서 오늘 이 부분에 대해서 고민을 해보았다.

그래서 ‘내가 Java의 어떤점에 감탄했는가?’에 대해 생각을 해 보았다.

먼저 ClassLoader: Java의 소스코들 컴파일 하면 나오는 *.class 파일을 소스코드상에서 로그인해 어플리케이션을 종료하고 않고도 로직을 바꿀 수있는개념이었다.

그 다음은 Thread: 커널레벨의 기능들을 추상화 해 놓아서 간편하게 사용할수있게해놓았다.

이렇게 두가지 정도 였다. 그런데 가만 생각해보니 두가지 모두 JVM의 역할 아닌가? 그렇다 그 찝찝함은 Java에 대한 나의 감탄은 Language가 아닌 JVM에서 온 것이었다.

얼마전 오라클이 구글에 건 소송 내용은 VM과 관련된 것이었다. 그만큼 JVM이 엄청나다는 것을 생각해보게 되었다. 하지만 나는 프로그래머이다 (정확히는 프로그래밍을 공부하는 사람) 그러한 VM을 구현해야하지 사용만 할 입장은 아닌 것 같다. 그래서 나의 자바에 대한 생각을 정리하면 “나는 Java라는 Language에서 매력을 느끼지 못한다. 그러나 JVM은 좋은 것 같다” 이다. 쉽게 말해 Java 안할꺼임


좋은 프로그래머?

 

요즘 성향이 다른 프로그래머들을 정말 많이 본다.
그분들의 이야기를 듣거나 블로그 등을 찾아가면 자신의 성향이 짙게 나타나는 것 같다.
가끔씩은 다른 쪽을 싫어하는 모습도 볼수 있다…

그런 모습을 보면서

“어느쪽을 타겟으로 해서 공부해 나갈지 모르겠다”

라고 생각하던중 문득 떠오른게


“성향이 달라도 모두 성공한 프로그래머 아닌가?”


이다… 그렇다면 내 나름대로의 모습을 가지고 그쪽에 대한 믿음을 가진다면 좋은 프로그래머가 될 수 있지 않을까?

살아가다보면 내 판단이 어떤지 언젠가 알 수 있겠지…


Tumblr를 시작했다

Tumblr의 깔끔함 이라는 것을 느껴보고 싶어서 다른 기능많은 블로그들 대신 Tumblr를 선택했다.