🧠 메모리를 직접 다루면 왜 복잡해질까?
한 줄 결론 : 직접 주소를 다루면 안전성·동시성·보안 문제를 개발자가 전부 책임져야 하기 때문이다.
💡 Java는 왜 포인터가 없을까?
C 언어에서는 이런 코드가 가능하다.
int* p = (int*)0x1000;
*p = 10; // 메모리 주소를 직접 조작
Java에서는 이런 코드를 아예 작성할 수 없다. 이유는 단순하다.
직접 주소를 다루면 4가지 치명적인 문제가 생기기 때문이다.
⚠️ 직접 메모리 접근의 4가지 문제
1. 메모리 충돌 (Memory Collision)
프로세스 A → 0x1000 사용
프로세스 B → 0x1000 사용 ← 데이터 덮어쓰기 발생!
서로 다른 프로그램이 같은 주소를 사용하면 데이터가 파괴된다.
OS가 가상 메모리(Virtual Memory) 를 도입한 이유가 바로 이것이다.
2. 메모리 누수 (Memory Leak)
int* p = malloc(100);
// free(p)를 호출하지 않으면?
// → RAM이 계속 점유됨 → 서버에서는 치명적
Spring Boot에서 GC(Garbage Collector) 가 존재하는 이유가 바로 여기에 있다.
개발자가 직접 해제하지 않아도 JVM이 사용하지 않는 객체를 자동으로 수거한다.
3. 잘못된 주소 접근 (Segmentation Fault)
int* p = NULL;
*p = 10; // 프로그램 즉시 종료
Java에서 포인터 직접 접근을 금지하고 JVM이 메모리를 추상화하는 이유가 여기에 있다.
잘못된 주소에 접근하는 순간 프로그램 전체가 크래시된다.
4. 동시성 문제 (Data Race)
Thread A → 주소 0x2000 수정 중
Thread B → 같은 주소 동시에 수정 ← 값이 꼬임!
이 문제를 해결하기 위해 등장한 개념들이다.
| 해결책 | 설명 |
|---|---|
synchronized | 블록 단위 상호 배제 |
volatile | 메모리 가시성 보장 |
CAS | 원자적 비교-교환 연산 |
🏗️ Java가 메모리를 다루는 방식
User user = new User();
개발자는 주소를 모른다. 하지만 내부에서는 이렇게 동작한다.
개발자 → 객체(변수명)로 접근
JVM → 힙(Heap)에 할당 & GC로 관리
OS → 가상 주소 관리
CPU → 물리 주소 접근
이 계층 구조 덕분에 개발자는 비즈니스 로직에만 집중할 수 있다.
📌 핵심 요약
| 문제 | 원인 | Java의 해결책 |
|---|---|---|
| 메모리 충돌 | 여러 프로세스가 같은 주소 사용 | JVM + 가상 메모리 |
| 메모리 누수 | 수동 해제 누락 | GC(Garbage Collector) |
| 잘못된 접근 | NULL·임의 주소 접근 | 포인터 직접 접근 금지 |
| 동시성 문제 | 멀티스레드 데이터 레이스 | synchronized / volatile / CAS |