Java & Kotlin/Java
Java 메모리(with. JVM) 관련 정리
전봉근
2022. 7. 27. 15:00
반응형
최근에 JVM 관련 대화를 나누던 도중 메모리 영역에 대한 잘못된 설명을 해버린적이 있다. 반성하는겸 다시 정리하고자 해당 포스팅을 작성하게 된다.
Java 메모리(with. JVM)
- 정의
- Stack: 정적 할당된 메모리 영역
- boolean, char, short, int, long, float, double.. 등과 같은 데이터 즉, 원시타입의 데이터가 값이랑 같이 Stack 에 할당된다.
- Heap 영역에서 Object 타입 데이터의 참조값이 Stack 에 할당된다.
- Stack 의 메모리는 Thread 당 하나씩만 할당된다. 즉, 새로운 Thread 생성시 그 해당 Thread 에 대한 Stack 이 또 새롭게 생성된며 각 Thread 끼리는 Stack 영역을 접근 할 수 없다.
- 간단한 사용예시
public class Test { public void getTest() { int num = 0; } }
- Heap: 동적으로 할당된 메모리 영역
- 계속 사용하니 생명주기가 길다.
- 여러 개의 Thread 가 있어도 Heap 에는 단 하나의 영역만 존재한다.
- Heap 에 생성된 객체 데이터를 참조하는 주소는 Stack 메모리에 생성된다.
- 간단한 사용예시
public class TestObj{} public class Test { public static void main(String[] args) { TestObj testObj = new TestObj(); } }
- Static: 단어 뜻 그대로 정적 메모리이며 컴파일 시간 동안 할당된 메모리이고 고정된 공간을 차지하므로 런타임 중에는 변경할 수 없는 특징을 가지고 있다. 주로 Singleton 과 같은 방식으로 잘 사용한다면 메모리 사용에 대한 이점을 볼 수 있지만 정적 메모리는 공유되는 자원으로써 멀티 쓰레드 환경에서 동시성을 보장하지않으므로 데이터 무결성과 정합성이 지켜지지 않을 수 있기 때문에 주의하자!
- 메모리의 데이터 영역에 변수가 저장 (데이터 영역은 프로그램의 시작과 함께 할당되며, 프로그램이 종료하면 소멸)
- 간단한 사용예시
public class Test { static int num; }
- Stack: 정적 할당된 메모리 영역
- 코드
- Example1
- Example2
// 상기 개념대로면 해당 출력이 "hello world Hi Hi" 로 되어야 되는데 실제 결과는 "hello world Hi" 이다. 왜 그런지 하기 코드를 통해 알아보자. public class Test { public static void main(String[] args) { // Stack 에 title 이라는 변수만 올라가고 실제 String 값은 Heap 영역에 올라가있고 여기서 참조하게 되어있다. String title = "hello world"; System.out.println("Before Title: " + title); // changeTitle 메소드의 파라미터인 String title 의 title 은 stack 에 올라가고 기존에 heap 영역에 생성된 String 값인 hello world 를 복사하고 그 복사된 값을 참조한다. // -> 원래 Example1 에서는 같은 값을 참조하게 되는데 여기서는 복사를 한다. 이유는 String 은 immutable(=변경할 수 없는) 한 클래스이므로 그렇다. (또한 Boolean, Integer, Long 등 과 같은 Wrapper 클래스들은 immutable 한 클래스로 쓰임, 반대인 mutable 한 객체는 List, ArrayList, HashMap 등의 컬렉션들이 대표적인 mutable 한 객체이다.) // -> 만약 문자열을 mutable 하게 사용하려면 StringBuilder 의 append 메소드를 사용하면 된다. // changeTitle 메소드에 s += " Hi"; 을 보면 복사된 값에 더해지는게 아니다. 동작하지 않는 이유는 += 연산자는 그대로 갖다 붙이는게 아니라 새롭게 Heap 영역에 생성된 곳에다가 참조하게 된다. (기존 연결된 참조는 끊긴다.) // 해당 메소드가 끝나면 메소드에서 사용된 Stack 영역에 올라가 있던 변수인 s 는 pop 된다. changeTitle(title); System.out.println("After Title 1: " + title); // 위의 설명대로 += 연산자이므로 새롭게 Heap 영역에 생성된 값을 title 변수에서 참조한다. title += " Hi"; System.out.println("Before Title 2: " + title); } public static void changeTitle(String s) { s += " Hi"; } }
- 여기서 연결이 끊기고 남아있는 객체들은 Garbage 이므로 GC(=Garbage Collector) 에서 제거해준다. (gc 에 대해 자세히 알고 싶으면 https://bkjeon1614.tistory.com/718 참고)
반응형