참조 카운팅 (Reference Counting)
여러 개의 객체들이 똑 같은 값을 가졌으면, 그 객체들로 하여금 그 값을 나타내는 하나의 데이터를 공유하게 해서 데이터의 양을 절약하는 기법
목적
1. Heap 객체를 둘러싼 내부 정보를 유지하는 작업을 단순하게 하자
2. 똑 같은 값을 가지고 있는 객체들이 그 값을 하나씩 꿰어차도록 놔두는 것은 낭비
목적 1> 어떤 객체가 new에 의해 할당되고 난 후에는, 그 객체의 주인이 누구인지 따라가야 하는 것은 숙명이자 운명입니다. new한 쪽에서 bew로 만든 포인터를 해제해야겠지요. 하지만 프로그램이 실행되면서 이 객체의 소유권이 이 객체에서 저 객체로 왔다 갔다 할 수 있기 때문에, 객체의 소유권을 추적하는 일은 상당히 까다롭습니다. 특히 포인터를 매개변수로 넘길 때 그렇죠.
이런 참조 카운팅은 객체 소유권을 추적해야 하는 고민을 없앱니다. 참조 카운팅 기능을 가진 객체가 자신의 소유권을 쥐고 있기 때문이죠. 아무도 자신을 사용하지 않으면 스스로 자신을 소멸시킵니다. 일종의 가비지 콜렉션이죠
목적 2> 똑 같은 값을 여러 객체가 메모리를 할당하여 쓰는 것은 낭비이자 비효율 적입니다. 똑같은 값을 가진 객체를 여러 번 생성하고 소멸해야 하니까요. 그 대신 그 값을 나타내는 데이터 하나만 공유하자는 겁니다. 메모리 절약은 물론, 속도도 빨라집니다.
기본부터 집고 넘어가 봅니다.
우선 똑 같은 값을 가진 객체가 여러 개 생길 수 있는 상황을 꾸며 봐야 하겠습니다.
String 클래스 |
class String { public: String(const char *value = ""); String& operator=(const String& rhs); ... private: char* data; }; String a, b, c, d, e; a = b = c = d = e = "Hello"; |
a부터 e까지 모두 똑 같은 값을 가졌을까요?
값을 어떻게 나타내느냐는 String 클래스를 어떻게 구현했느냐에 따라 달라지겠지만, 흔히 생각할 수 있는 방법은 String 객체 각각이 그 값의 사본을 하나씩 갖게 하는 것입니다. 아래처럼요
String.cpp |
String& String::operator=(const String& rhs) { if (this == &rhs) return *this;
delete [] data; data = new char[strlen(rhs.data) + 1]; strcpy(data, rhs.data);
return *this; } |
String 객체 a,b,c,d,e는 아래처럼 값을 가지고 있겟죠.
a -> Hello
b -> Hello
c -> Hello
d -> Hello
e -> Hello
이래저래 낭비되고 있습니다. 아래처럼 바꾸는게 목적입니다.
b ->
c -> Hello
d ->
e ->
(모든 화살표가 하나의 'Hello'를 가르키고 있습니다. 착해야 보입니다)
“Hello” 사본 하나만 저장되고, String 객체 여러 개가 이 데이터를 공유합니다.
그런데, 문제가 있습니다. 객체 a에 “Hello” 이외의 값이 대입된다고 해도 “Hello”를 소멸시키면 안되죠. b~e가 유효범위를 벗어날 때 “Hello”라는 값을 가진 객체의 수는 0이 되기 때문에 그 값을 소멸시켜야 하구요.
즉, 그 값을 공유하고 있는 객체의 개수에 대한 정보가 필요하게 됩니다.
다른 말로 하면, 참조 카운트인거죠. 위의 그림은 아래와 같이 되어야 합니다.
b ->
c -> (5) -> Hello
d ->
e ->
(마찬가지로, 모든 화살표가 하나의 '5'를 가르키고 있습니다.)
그럼 참조 카운팅 구현은 어떻게 하느냐
다음에 ….
<출처>
1. More Effective C++, 정보문화사, 스캇 마이어스