[C#] 문자열은 불변

spixychz·2025년 11월 20일

기술면접

목록 보기
4/15

string은 참조 타입에 불변

불변(Immutable): 동일한 메모리 주소에 값 다시 쓰기가 불가능. 매번 새로운 메모리 주소에 값을 넣는다.

왜 참조타입일까 ?

string a = "Hello";		// Heap에 문자열 객체 생성. a는 문자열 객체의 주소를 가리킴
string b = a;			// b는 a가 가리키고 있는 주소 복사
  • 크기를 예측할 수 없는 가변성
    => 변수는 주소만 저장하고, 실제 데이터는 Heap 메모리에 저장
  • 변수를 다른 변수에 할당하거나 인자로 전달할 때마다 텍스트가 복사되면 메모리 효율에 악영향
  • 참조 타입으로 주소만 저장하는 것이 훨씬 효율적

왜 불변일까 ?

string a = "Hello";
string b = a;

b = "World";

Console.WriteLine(a);	// 결과 : "Hello"
Console.WriteLine(b);	// 결과 : "World"
  • string 객체는 생성되면 그 내부 텍스트 데이터를 절대로 수정할 수 없다.
  • 수정처럼 보이지만 새로운 객체를 생성하고 그 주소를 참조하게 되는 것.
string a = "Hello";
a += " World";
  • 위 경우에서는 "Hello" 문자열이 수정되는 것이 아니라, "Hello World"라는 새로운 문자열 객체가 만들어진다.
    즉, a가 "Hello World"라는 객체로 참조를 바꾼 것이지 기존의 "Hello" 객체는 그대로 유지된다.
  • "Hello"는 인턴풀에 존재하고, "Hello World"는 힙 메모리에 존재하기 때문에 더 이상 참조되지 않으면 GC의 대상이 된다.

불변 객체인 이유

  • 예측 가능한 동작
    • 같은 문자열을 여러 변수가 참조해도, 문자열을 바꿔서 전체가 영향을 받는 상황을 막기 위해
  • 해시 일관성
    • Dictionary, HashSet 등에서 key로 문자열을 사용할 때, 값이 불변이면 해시가 안정
  • 스레드 안정성
    • 여러 스레드가 동시에 같은 문자열을 읽어도 문제가 없게
  • 메모리 최적화 (Intern Pool)
    • 자주 쓰이는 리터럴 문자열을 한 번 생성하여 재사용함으로써 메모리 절약
  • 보안성
    • 외부에서 참조 중인 문자열을 의도치 않게 수정하는 것을 방지

문자열을 생성하는 방법

  • 리터럴 문자열
    • 코드 안에 직접 작성된 문자열 값
    • ex) "Hello", "AB" + "CD" ("ABCD"로 저장)("AB" + this.name 이런건 안됨)
    • Intern Pool에 저장
  • 런타임 생성 문자열
    • ex) new string(), ToString(), SubString() ...
    • 일반 힙에 저장
    • 참조가 끊기면 GC 대상

Intern Pool

동일한 문자열(리터럴)을 한 번만 만들고 재사용하기 위한 런타임 전역 캐시

  • 자주 쓰이는 고정 문자열의 메모리 사용 최적화
  • string.Intern()
  • 인턴된 문자열은 프로세스 수명동안 유지
    • 무분별한 인턴은 영구 캐시 증가
  • 런타임에 존재하는 메모리 구조지만, 최초 포함되는 목록은 컴파일 시점에 결정
  • CLR(Common Language Runtime)이 관리
string a = "ABC";
string b = "ABC";

Console.WriteLine(object.ReferenceEquals(a, b));    // 결과 : True

string c = new string("ABC");
string d = string.Intern("ABC");

Console.WriteLine(object.ReferenceEquals(a, c));    // 결과 : False
Console.WriteLine(object.ReferenceEquals(a, d));    // 결과 : True
Console.WriteLine(object.ReferenceEquals(c, d));    // 결과 : False

string e = string.Intern(new string("ABC"));

Console.WriteLine(object.ReferenceEquals(a, e));	// 결과 : True
Console.WriteLine(object.ReferenceEquals(c, e));	// 결과 : False

StringBuilder

문자열을 반복 수정하기 위한 가변(mutable) 문자열 클래스

문자열을 자주 연결하거나 변경하면 매번 새로운 문자열 객체를 생성하게 되어 GC의 부담이 커진다.
=> 이럴때 사용하는 것이 StringBuilder

  • 수정 가능한 내부 char[] 버퍼 재사용하여 문자열 조립
  • ToString()을 호출할 때만 문자열 객체 생성
  • 참조 타입이면서 가변적

결론

string이 참조 타입이자 불변 객체인 이유는 ?

많은 코드에서 공유되어 사용되는 문자열이 안전하고 예측 가능하게 동작하도록 하기 위해서

profile
UNITY로 게임 개발하는 사람

0개의 댓글