아무거나

Java 메모리(with. JVM) 관련 정리 본문

Java/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;
        }
        
  • 코드
    • 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 참고)

 

반응형

'Java > Java' 카테고리의 다른 글

Spring Batch 6편 - Chunk-Oriented Processing  (0) 2022.11.06
Java Stream 이란  (0) 2022.08.11
Garbage Collection (요약정리본)  (0) 2022.07.27
Java 의 Optional 개념과 올바르게 사용하는 방법  (0) 2022.07.22
JDBC 동작과정  (0) 2022.01.07
Comments