상세 컨텐츠

본문 제목

[매일메일] String 객체는 가변일까요, 불변일까요?

본문

이건 거짓말 안하고 한 번도 생각안해봤다.

불변이라면, 한번 생성하고나면 변하지 않는다는 말일 것이다.

예를 들어서

s = "hello"
s = s + "world"

이렇게 적혀있다면, hello world 라는 새로운 문자열 객체가 만들어진 것일 뿐 기존 hello는 변하지 않는다고 한다.

이 말은, hello라는 문자열이 저장된 메모리 주소가 있을 것이고 s는 해당 위치를 지칭할 것이다. 이때 hello + world가 되게 되면, hello라고 저장된 메모리 위치에서 수정이나 hello world라는 문자열로 덮어쓰기가 일어나는 것이 아닌 해당 객체가 새로운 메모리 주소로 할당되며 생성되고 s는 새롭게 해당 주소를 지칭하게 된다. 여기까지는 이해가 되는데 그렇다면 왜 이렇게 만들었을까.

 

이점 :

  • String Constant Pool을 사용할 수 있음. (JAVA에서 나온 개념으로 GC의 대상이 되지 않음)
    • 동일한 문자열의 String 변수들은 같은 객체를 공유하기 때문에 메모리를 효율적으로 사용할 수 있음
    • 불변한 객체는 멀티 스레드 환경에서 thread-safe함. String Constant Pool에 새로운 객체를 생성하기 때문에 동기화를 신경 쓸 필요 없음
    • 해시 코드를 한 번만 계산하고, 이를 캐싱해서 재사용할 수 있음
    • 민감한 정보에 관련한 관리가 편하고 안전하게 가능
String first = "hello"; // 리터럴로 생성
String second = new String("hello"); // 생성자로 생성
String third = "hello";

System.out.println(System.identityHashCode(first)); // 498931366
System.out.println(System.identityHashCode(second)); // 2060468723
System.out.println(System.identityHashCode(third)); // 498931366

해당 두 객체는 다른 객체임. 리터럴로 생성한 String 객체는 Heap영역의 String Constant Pool에 저장되어 동일한 문자열을 재사용 가능함.

 

반면, 생성자로 생성한 String 객체는 Heap영역에 저장되어 동일한 문자열이더라도 항상 새로운 객체 생성함.

String third = second.intern(); // intern() 메서드 사용
System.out.println(System.identityHashCode(third)); // 498931366

intern() 메서드를 사용하면 Heap 영역에 저장된 String객체를 String Constant Pool에 저장 할 수 없음.

intern() 메서드는 해당 문자열이 String Constant Pool에 존재할 경우 그 주솟값을 반환하고, 없을 경우 String constant Pool에 추가하고 새로운 주솟값을 반환

 

그렇다면 파이썬도 비슷한 게 있나?

챗지피티로 물어본 결과

생성자로 만든 문자열은?

 

자바처럼 무조건 새 객체는 아님. 이미 문자열이 있다면, 그냥 그 객체를 반환해줌

-> intern()을 sys라이브러리의 내부 함수로 사용 가능함. 하지만 항상 intern되는 것은 아님.

짧은 리터럴, 영문자/숫자/언더 스코어로만 된 문자열 등 일부만 자동 intern

복잡하거나 동적으로 만들어진 긴 문자열은 필요에 따라 intern 해야 공유 가능

 

하지만, 결론적으로 파이썬도 자바처럼 문자열 불변성, 상수 객체 공유 구조는 존재함.

관련글 더보기