들어가기
코딩 테스트 문제를 풀면서 의문이 든 점이 있었다.
String을 활용하여 문자열을 다룰 수 있는데 왜 StringBuilder를 사용하여 append(), delete()와 같은 메서드를 사용하여 문자열을 수정하는 것일까?
처음에는 단순히 가독성 때문이라고 생각을 하였지만, 알고 보니 StringBuilder를 사용하는 것이 더 효율적이기 때문이었다.
효율성이 나는 이유는 String은 불변 객체로서 문자열을 저장하고, StringBuilder는 가변 객체로서 문자열을 저장하는 것에서 비롯된다.
그렇다면 둘다 같은 문자열을 저장하는 객체인데 어떻게 차이가 나는 것인가?
또한 String은 불변 객체이지만 어떻게 아래와 같이 문자열에 추가로 대입할 수 있는 것인가?
String temp = "test";
temp = temp + "tt";
이 글에서는 이러한 의문들을 가지고 메모리 공간과 연관되어 String, StringBuilder, StringBuffer에 대해서 설명할 것이다.
본론
우선 데이터가 어떻게 저장되는지 간단하게 알아보겠다.
자바 프로그램을 실행 시 JVM 위에서 프로그램이 돌아가고, OS는 필요한 메모리 공간을 할당해 준다.
메모리 공간은 크게 힙(Heap), 스택(Stack), 메서드(Method) 영역으로 구분된다.
힙 영역은 동적 데이터가 할당되는 곳으로 new 키워드로 생성되는 객체(인스턴스), 배열 등이 저장된다. 가비지 컬렉션에 의해 메모리가 관리된다는 특징이 있다. 스레드가 몇 개가 존재하든, 단 하나의 영역만 존재한다. 그렇기에 멀티 스레드 환경에서 공유 자원에 경우 동시에 접근할 수 있는 문제가 발생하기에 synchronized 키워드(특정 메서드나 블록에 대해 스레드가 한 번에 하나씩만 접근하도록 제어)와 같이 대비를 해야 한다.
스택 영역은 지역 변수와 매개 변수 데이터 값이 저장되는 영역으로, 메서드가 호출될 때 메모리에 할당되고, 호출이 종료되면 메모리가 해제된다. LIFO(Last In First Out) 구조를 갖고 변수에 새로운 데이터가 할당되면 이전 데이터는 지워진다.
메서드 영역 : 전역변수와 static변수를 저장하며 프로그램의 시작부터 종료까지 메모리에 남아있다. 힙 영역과 동일하게 모든 스레드가 공유하는 영역이다.
지역 변수로서 선언한 int, double과 같은 기본형 변수는 스택에 저장된다.
하지만 Integer, Double과 같은 참조형 변수는 스택에 참조 주소만 저장되고 실제 객체는 힙에 저장된다.
그렇다면 String은 어떨까?
만약 new 키워드를 사용하여 문자열을 지정 시 다른 참조형 변수와 동일하게 실제 객체는 힙에 저장된다.
하지만 직접 문자열을 String에 지정할 경우 실제 값은 스트링 풀(String Sool = String Contant Pool)에 저장이 된다.
String pool은 힙 내에 문자열이 저장되는 공간으로 동적 객체가 저장되는 힙과는 분리된 공간으로 여긴다.
여기서 String 객체가 왜 불변 객체인지를 확인할 수 있다. str은 String 변수를 저장한 참조 값만을 스택에 저장할 뿐, str을 변경하면 새로운 문자열이 String Pool에 계속 누적하게 되는 것이다.
이로 인해서 이미 한번 저장된 문자열은 새로 저장 없이 가져올 수 있는 캐싱 기능을 수행할 수 있다.
하지만 String Pool에 저장한 값은 가비지 컬렉션에 의해서 힙 영역이 정리될 때, 같이 정리되지 않는다.
String pool은 프로그램 종료 시 해제되기 때문에 새로 생성되는 문자열은 계속 저장되어 있는 상태이다.
즉, JVM이 시작할 때 초기화되며 내부 공간은 종료될 때까지 유지가 된다.
일반적인 경우에는 메모리가 부족함 없이 할당되어 문제가 발생하지 않지만, 매우 많은 문자열을 저장해야 할 경우에는 신경을 써줘야 하는 부분이다.
그렇기에 코딩테스트 문제를 풀 때 String을 직접 다루기보다는 StringBuilder를 활용하는 것이 더 효율적인 것이다.
그렇다면 StringBuilder로 지정한 문자열은 어디에 저장될까?
바로 String pool이 아닌 힙 영역에 저장된다.
StringBuilder는 동적 객체로서 저장하고, append(), insert(), replace(), delete(), setCharAt() 등과 같이 여러 메서드를 통해 문자열 값을 수정해도, 새로 문자열을 추가하는 것이 아니라 힙 영역에 이미 존재하는 문자열 값이 수정된다.
이렇기에 가변 객체라고 할 수 있으며, 문자열 값의 변화가 많은 경우 StringBuilder로 선언하는 것이 유리하다.
여기서 한 가지 더 언급하자면 StringBuilder와 유사하게 사용되는 StrinbBuffer가 있다.
StringBuilder와 마찬가지로 StringBuffer 또한 가변 객체로 힙 영역에 저장한다.
다만 StringBuffer는 멀티 스레드 환경에서 동기화가 일어난다는 것이다. 그렇기에 단일 쓰레드 환경에서는 StringBuilder, 멀티 쓰레드 환경에서는 StringBuffer을 사용할 수가 있다.
결론
이렇게 간단하게 자바에서 사용되는 String 객체가 왜 불변 객체인지, 메모리에 어떻게 저장되는지를 확인할 수 있었다.
프로그램에서 문자열은 매우 많이 사용되는 값이며, Java를 활용하는 개발자로서 가장 기본이라고 할 수 있는 String에 대해서 확실히 이해하고 넘어가는 것이 중요하다고 생각하기에 이렇게 간단하게 글을 작성하게 되었다.
마지막으로 String, StringBuilder, StringBuffer에 대해 요약 정리하며 이 글을 마치겠다.
불변성 | 동기화 | 성능 | 사용 | |
String | 불변 | 없음 | 느림(새 문자열 객체 생성 시) | 문자열이 변경되지 않는 경우 |
StringBuilder | 가변 | 동기화(thread-safe) | 상대적으로 느림(동기화 오버헤드) | 멀티 쓰레드 환경에서 가변적인 문자열을 다루는 경우 |
StringBuffer | 가변 | 없음 | 빠름 | 싱글 쓰레드 환경에서 가변적인 문자열을 다루는 경우 |
잘못된 내용이나 궁금한 사항은 댓글 남겨주시면 감사합니다!
참고
https://ict-nroo.tistory.com/18
[JAVA] String = " " vs new String(" ") 의 차이
■자바의 String에 대해 잘 안다고 말할 수 있을까? 신용권님이 쓰신 이것이 자바다 책을 두번째 학습하는 중이다. 확실히 느끼는 건데, 1회독과 2회독의 느낌은 정말 다르다는 것을 느끼면서 책을
ict-nroo.tistory.com
https://www.digitalocean.com/community/tutorials/what-is-java-string-pool
What is Java String Pool? | DigitalOcean
While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.
www.digitalocean.com
https://deveric.tistory.com/123
[Java] 많이 헷갈려하는 String constant pool과 Runtime Constant pool, Class file constant pool
String Constant Pool과 Constant Pool 이 두 가지는 완전히 다른 개념입니다. 용어가 비슷한 형태이기 때문에 이 두 가지를 혼용하여 헷갈리는 경우가 많습니다만, 저장되는 위치부터 저장하는 데이터의
deveric.tistory.com
https://lucas-owner.tistory.com/38
[Java] Java 메모리 영역(stack, heap, static), JVM, JAVA 변수 종류
목차 JVM 이란? Java의 메모리 영역 Java 변수 종류 Static(Method) 영역 Heap 영역 Stack 영역 JVM 메모리 구조중, (Stack, Heap, Static)메모리 영역과 JVM, Java 변수 종류에 대해서 알아보자. JVM 이란? - 메모리 영
lucas-owner.tistory.com
https://dev-coco.tistory.com/153
신입 개발자 기술면접 질문 정리 - 자바
💡 Java의 특징을 설명해주세요. Java는 객체지향 프로그래밍 언어입니다. 기본 자료형을 제외한 모든 요소들이 객체로 표현되고, 객체 지향 개념의 특징인 캡슐화, 상속, 다형성이 잘 적용된 언
dev-coco.tistory.com
'JAVA' 카테고리의 다른 글
자바 StringBuilder를 통해 빠르게 출력하기 (0) | 2021.12.08 |
---|---|
자바 입력, 출력 시 BufferedReader, BufferedWriter를 사용해보자! (0) | 2021.11.22 |
자바기본개념 - 자바가상머신 및 가비지 컬랙션 (0) | 2021.10.22 |
자바 핵심 기본 내용 (0) | 2021.10.17 |
java - Priority Queue(우선순위 큐) (0) | 2021.10.05 |