string vs String

string a;
String b;
  • 두 타입 모두 System.String 타입으로 동일

String Pool

  • 선언 방식에 따라 변수가 저장되는 위치 결정
string str1 = "asdf";             // str1 -> 스택, "asdf" -> 힙의 string pool
string str2 = new string("asdf"); // str2 -> 스택, "asdf" -> 힙
  • str1의 문자열은 힙의 string pool 에 저장되어, 이후 같은 문자열이 사용되면 저장소를 공유한다
  • str2의 문자열은 공유되지 않는다

eqauls() vs. ==

string str1 = "asdf";                       // str1 -> 스택, "asdf" -> 힙의 string pool 공유
string str2 = new string("asdf");           // str2 -> 스택, "asdf" -> 힙 별개 주소 
string str3 = "asdf";                       // str3 -> 스택, "asdf" -> 힙의 string pool 공유
string str4 = new string("asdf").intern();  // str4 -> 스택, "asdf" -> intern 함수를 통해 힙의 string pool 공유

str1 == str2; // false
str1 == str3; // true
str1 == str4; // true
  • == 는 두 객체가 동일한 객체인지 주소값을 비교
  • equals는 두 객체의 값을 비교

intern pool

  • 문자열 하나가 생성되면 이는 하드코드된 상수 문자열이며, 인턴 문자열이다
    • 리터럴 문자열 Literal string이라 한다
  • 위의 리터럴 문자열을 CLR이 모아놓은 테이블이 인턴 풀
    • 인턴 풀에 존재하는 문자열 객체는 힙에 존재하지 않으며, GC 대상이 아니다

인턴 풀 존재 이유?

  • 문자열이 선언되고 2회 이상 사용된다면 2개의 동일한 문자열을 새롭게 생성할 필요가 없다
  • 위의 사실에 기반했을 때, 인턴 풀에 추가된 문자열은 언제 재사용될지 알 수 없으므로 GC의 대상이 아니다
    • 힙에 위치할 수 없다

StringBuilder

string은 불변객체

  • string 객체에 새로운 문자열을 대입할 시, 그 문자열은 pool에 새롭게 저장
  • 기존 문자열은 pool에는 남아있으나 더 이상 참조되지 않는다
    • 기존 문자열을 참조하던 string 객체는 GC에 의해 수집
    • 이 같은 상황이 반복되면 메모리와 퍼포먼스에 영향을 준다
      • intern pool이 너무 커지면 안된다는 뜻인가…?
string str = "2022" + "July" + "17th";
  • 위의 객체는 3개의 string 객체가 조합되어 생성되며, 이중 2개 string 객체는 조합 이후 GC에 의해 수집된다
    • 리터럴 문자열 자체는 intern pool에 남아있다

StringBuilder는 가변객체

  • 문자열이 변경될 시, 자동으로 참조하는 메모리를 변경
  • System.Text.StringBuidler 클래스의 내부 함수를 실행
    • 하나의 객체에서 값들을 조합 및 삭제 메모리 낭비 방지
  • 오버헤드를 넘지않는 케이스에서의 사용은 오히려 성능을 저하시킬 수 있다
    • 문자열 수정이 빈번하거나 반복적일 때
    • 많은 수의 문자열 조합이 필요한 경우
    • 동일한 이유로 string + string 보다 StringBuilder의 Append가 적합한 경우가 있다

출처

카테고리: ,

업데이트: