Skip to main content

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를 쓰는 게 더 효율적이다.