Java: 기본형(int) vs String(불변 객체)의 메모리 구조 비교
1. Java의 메모리 구조
Java 프로그램은 크게 세 가지 메모리 공간을 사용한다:
1.1 Stack 영역
- 지역 변수 및 기본형(primitive type) 값 저장
- 메서드 호출 시마다 프레임이 생성되고, 종료되면 자동으로 해제됨
- 매우 빠르며, GC 대상이 아님
1.2 Heap 영역
new
연산자 등을 통해 생성된 객체가 저장됨ArrayList
,String
,Integer
, 사용자 정의 클래스 등- GC(Garbage Collector)에 의해 관리됨
1.3 String Constant Pool (리터럴 풀)
- Heap 내부의 특별한 공간
- 동일한 문자열 리터럴을 공유하여 메모리 절약
"hello"
와 같은 리터럴은 Pool에서 재사용됨
2. 기본형 변수 (예: int
)
기본형은 값 그 자체가 Stack 메모리에 저장된다. 변수 간의 대입은 값 복사이며, 변수 간 영향이 없다.
2.1 코드 예시
int a = 10;
int b = a;
a = 20;
2.2 메모리 흐름
초기 상태:
[Stack]
a → 10
b → 10 (값 복사됨)
a = 20; 이후:
a → 20
b → 10 (영향 없음)
📌 int
는 값 자체(value) 를 저장하며, 변수 간 대입은 값 복사다.
값을 변경해도 기존 변수나 참조에 영향을 주지 않는다.
3. String (불변 객체)
String
은 참조형(reference type) 객체이며, Stack에는 참조만 저장되고 실제 문자열은 Heap 또는 Constant Pool에 존재한다.
3.1 코드 예시
String s1 = "hello";
String s2 = s1;
s1 = s1 + " world";
3.2 메모리 흐름
[초기 상태]
[Stack] [Heap (String Pool)]
s1 ─┐ "hello"
└────────▶
s2 ─┘ (s1, s2 둘 다 "hello" 참조)
[변경 후]
[Stack] [Heap]
s1 ──────────▶ "hello world" ← 새 객체 생성
s2 ──────────▶ "hello" ← 원본 유지
→ s1 + " world" 는 기존 "hello"를 수정하는 것이 아니라
**"hello world"라는 새로운 객체를 생성**
📌 String
은 불변(immutable) 이기 때문에 수정이 아닌 새 객체 생성 방식으로 동작한다.
따라서 반복 수정이 많으면 Heap에 객체가 누적 → GC 부담 증가 가능.
4. 예제 비교 요약
// 기본형
int a = 10;
int b = a;
a = 20; // b는 여전히 10
// 참조형 (String)
String s1 = "hi";
String s2 = s1;
s1 = s1 + "!"; // s2는 여전히 "hi"
항목 | 기본형 (int 등) | 참조형 (String) |
---|---|---|
저장 위치 | Stack | Stack(참조), Heap(객체) |
대입 방식 | 값 복사 | 참조값 복사 |
수정 시 영향 | 원본과 무관 | 불변 → 새 객체 생성 |
메모리 부담 | 없음 | 반복 수정 시 Heap 객체 증가 가능 |
5. 요약 및 실무 팁
- 🔹 기본형은 값 자체를 Stack에 저장 → 변경 간섭 없음, 매우 빠름
- 🔹 String은 참조형이며 불변 → 수정 시 마다 새 객체 생성
- 🔸 반복적인 문자열 연결/수정이 필요한 경우 →
StringBuilder
사용이 권장됨
// 비효율 (String)
String result = "";
for (int i = 0; i < 1000; i++) {
result += "a"; // 1000개 객체 생성
}
// 효율적 (StringBuilder)
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
sb.append("a");
}
String result = sb.toString(); // 단 1개 객체 사용
6. 관련 참고
- 불변 객체:
String
,Integer
,Boolean
,LocalDate
- 가변 객체:
StringBuilder
,ArrayList
,HashMap
📌 불변성 덕분에 String은 안정적이고 안전하지만, 반복 수정 시에는 가변 객체 사용이 메모리 효율에 유리하다.
1. Java 의 메모리 구조
세 가지 메모리 영역
- Stack : 지역 변수, 기본형 변수 저장 (`int`, `boolean`, etc)
- Heap : `new` 키워드나 객체 생성 시 사용 (`String`, `ArrayList`, etc)
- String Constant Pool : 같은 문자열 리터럴을 재사용하는 공간 (Heap 내부 특수 영역)
2. 기본형 변수(int 등)
값 자체가 Stack에 저장됨
int a = 10;
int b = a;
a = 20;
📌 메모리 흐름:
[Stack]
a → 10
b → 10 (복사됨)
a = 20; 이후
a → 20
b → 10 (영향 없음)
- int는 값(value) 자체가 저장되므로 대입 시 값만 복사됨
- 변경해도 다른 변수에 영향 없음
3 . String (불변 객체)
참조값이 Stack에, 실제 값은 Heap/String Pool에 저장
String s1 = "hello";
String s2 = s1;
s1 = s1 + " world";
📌 메모리 흐름:
초기 상태:
[Stack] [Heap (String Pool)]
s1 ─┐ "hello"
└────────────▶
s2 ─┘
변경 후:
[Stack] [Heap]
s1 ──────────────▶ "hello world" ← 새 객체 (불변성)
s2 ──────────────▶ "hello" ← 원본은 그대로 유지
- s1 + " world"는 기존 문자열을 수정하지 않고, 새로운 문자열 객체 생성
- 기존 "hello"는 s2가 여전히 참조 중
- 따라서 메모리 활용방식이 더 복잡 (GC 대상 증가 가능)
4. 예제 비교
// 기본형
int a = 10;
int b = a;
a = 20; // b는 여전히 10
// String
String s1 = "hi";
String s2 = s1;
s1 = s1 + "!"; // s2는 여전히 "hi"
- 기본형은 값 그 자체를 다루고, 수정 시 그냥 덮어쓰기
- String은 객체의 참조를 다루며, 수정 시 새 객체 생성 = 불변성 유지
이 불변성 덕분에 String은 안정적이고 안전하지만, 반복 수정이 많을 땐 StringBuilder를 쓰는 게 더 효율적이다.