String Literal In C# Unity

Unity C#에서 String 객체를 남발하면 GC에 엄청난 먹잇감이 된다는 것은 익히 알려진 사실이다. 그래서 String 사용에 대해서 최대한 조심스러울 수 밖에 없다.

어떠한 경우에든 개발을 하다 보면, 아래와 같이 특정 String을 Double Quota 안에 넣어서 상수 형식으로 사용해야 할 때가 있다. 이 경우 저 String의 메모리 할당은 어디서 일어날까? 저렇게 남발하여 사용하여도 C#에서 문제가 없는 것일까?

 

 

정답부터 이야기 하자면 “문제 될 것이 없다” 이다.

C#이나 Java는 내부적으로 Global String Pool을 가지고 있다. 이 Pool에 저장된 각각의 String은 고정값(const)이고 변경이 불가능한(immutable) String 이다. 컴파일 시에 String Literal, 즉 위와 같은 상수값 String 문자열을 이 곳에 저장하게 된다. 이 String Pool은 특별한 목적의 일종의 Heap이라고 보면 되는데 C#에서 메타 데이터 형태로 저장된 String Literal을 저장하는 Heap이다. 또한 해당 패키지의 모든 class들이 볼 수 있는 Global 타입이다.

이렇게 Global Pool에 String List를 저장하는 장점은 두가지 이다.

1) 메모리 절약 / 매번 String Literal이 생성될 때마다 메모리를 생성시키지 않아도 되고, 동일 String Literal에 대해서 하나의 String Literal만 가지면 된다. (Immutable이기 때문에 변경 될 경우 새로 생성한다.)

2) Compare 연산이 빠르다. (String Pool의 String Literal을 저장하고 있는 String 변수들은  Reference가 동일하기 때문에 Deep Comparison을 하지 않고 그냥 Refrence만 비교하는 Shallow Comparison만 필요 하므로 결과 값을 빠르게 알 수 있다.)

 

C#에서 string.Equals 구현 참고(Implementation of string.Equals: C#)

 

아래의 str1과 str2는 String Pool에 저장되는 String Literal들이고, 동일한 Reference를 가진다.

 

 

반면 new 를 사용하여 runtime시에 생성된 string은 String Pool에 들어가지 않는다.

따라서 위와 같은 String Literal을 반복하여 사용하더라도 String Pool의 크기만 조금 늘어날 뿐 미친 듯이 많이 사용하지 않고서야 문제 될 것이 없다. 더군다나 동일한 String Literal은 추가 메모리가 생성되는 것이 아니고 기존 String Pool의 String Literal을 공유하게 된다.

C#이나 Java에서 이런 String을 Global String Pool에 동적으로 runtime 시에 집어 넣을 수도 있는데, 이것을 Interning이라고 한다. 또한 이런 interning된 string을 interned string이라고 부른다.

 

 

위의 코드에서 s1을 interning하여 s2를 사용하게 되면 비교 연산이 빨라 질 수 있게 된다. 따라서 Performance 적인 측면에서 String Comparison이 과하게 발생하는 부분이 있다면 Interning을 고민해야 한다. 파레토의 8:2 법칙에서 2에 해당한다면 말이다. ㅎ 물론, Interning 자체에 대한 비용이 엄청나니 프로그램 시작시에만 조심스레 사용해야할 것이다. 또한 같은 string 패턴 비교가 자주 발생하는 곳이 아니라면 Deep Comparison으로 넘어가기에 큰 유익이 없다. 

아래는 Interned string과 regular string의 10000번 비교 연산 시의 Performance 차이다.

 

No string.Intern:   1540 ms
With string.Intern:  736 ms [faster]

특정 String을 Interning 했을 때 기존에 Pool에 존재하는 경우 Reference를 리턴하고 없을 경우에 새로 Pool에 생성하여 Reference를 리턴한다.
references :

http://www.xyzws.com/javafaq/what-is-string-literal-pool/3
http://stackoverflow.com/questions/2423111/strings-and-garbage-collection
http://www.dotnetperls.com/string-intern
http://www.dotnetperls.com/string-literal
http://stackoverflow.com/questions/8509035/why-only-literal-strings-saved-in-the-intern-pool-by-default
http://csharpexperiments.blogspot.kr/2013/04/string-interning.html