회고록 블로그

[공부 필기] Java 기본 공부하기 (25) 본문

2. 프로그래밍 언어 공부/Java

[공부 필기] Java 기본 공부하기 (25)

김간장 2021. 12. 1. 22:34

공부 중인 강의 : 윤성우 선생님, 윤성우의 열혈 Java 프로그래밍 강의.

링크 : https://cafe.naver.com/cstudyjava

 

윤성우의 프로그래밍 스터디그룹 [C/... : 네이버 카페

윤성우의 스터디 공간입니다. C와 JAVA를 공부하시는 분들은 모두 들어오세요. ^^

cafe.naver.com

 

개인적인 소망으로는 Java 문법을 공부하면서 언젠간 꼭 배워놔야겠다고 생각한 내용 중 일부가 'JVM의 구조'와 '자바의 런타임 메모리 구조'였는데 이번 강의를 통해 간단하게나마 배울 수 있으면 좋겠다.

 


1. JVM 메모리 모델

- JVM은 메모리 공간을 세 개의 영역으로 구분해놓고, 각 영역에 여러 자료를 올려놓고 지우기도 함

   → 빨리 필요한 자료를 찾고, 제거하기 위해서

세 개의 영역 : 메소드 영역 / 스택 영역 / 힙 영역

   → 메소드 영역 = 메소드의 바이트코드, static 변수 등이 있음

   → 스택 영역 = 지역변수, 매개변수 등이 있음

   → 힙 영역 = 인스턴스가 들어감

 

2. 메소드 영역

- 메소드 영역은 바이트코드와 static 변수가 담겨있음

   → 바이트코드? 소스파일(*.java)을 컴파일하면 클래스 파일(*.class)이 되는데 그 클래스 파일 안에는 바이트코드가 있음

 

- 왜 "바이트코드"는 메소드영역에 있는걸까

   → 바이트코드를 보면 @@을 실행하라, ㅁㅁ를 실행하라 등 어떤 작업을 수행(실행)하라는 명령들이 가득 적혀있다고 함

   → 무언가를 실행하려면 메인(main) 메소드를 시작으로 다른 메소드를 호출하고 또 호출해서 처리해야함

   → 즉, (코드의 흐름을 쭉 따라가보면) 메소드의 호출로 이루어져 있다는 것을 알 수 있음

   → 그래서 바이트코드를 뜯어보면 메소드의 바이트코드가 대부분이라고 함

        * 바이트 코드를 읽어보면 대부분이 메소드의 바이트코드라고 해도 과언이 아니라고..

        * 이 내용을 기반으로 추측해보면, 바이트코드의 "거의 대부분"이 메소드 바이트코드이기 때문에

           (전체) 바이트코드를 굳이 굳이 메소드 따로, 그 외 기타 따로 등으로 쪼개지 않고

           그냥 메소드 영역에 하나로 올려놓은듯함

 

- 어쨌든, 중요한 점은 메소드 영역에 올라가는 바이트코드는 "전체 바이트코드"라고 함

 

 

# 참고. 임의의 소스코드를 컴파일하고(= 클래스 파일로 만들고)

              그 클래스 파일을 디어셈블(기계어를 어셈블리어로 변환) 해보면 아래와 같이 보임

 

- 또 한 가지 알아둬야할 점은 static 변수도 메소드 영역에 있다는 것

 

- JVM이 한 임의의 클래스 정보를 읽었다고 가정하자. (e.g. 인스턴스 생성)

   이때 JVM은 [메소드 영역]에 해당 클래스의 [바이트 코드]를 올림 (메소드의 바이트코드 뿐만이 아니라 전체를)

- 그리고 이때 임의의 클래스 안에는 static 변수가 자리를 잡고 있었다고 가정하자.

   JVM은 해당 클래스의 정보를 읽어들이는 그 순간에 [static 변수][메소드 영역]에 할당함

   → 할당하는 것뿐만 아니라 초기화까지도 끝내버림(초기화를 따로 하지 않은 경우 0으로 초기화)

 

- 왜 "static변수(클래스변수)"는 메소드 영역에 있는걸까

   → 사실 바이트코드와 static 변수는 공통점이 있음

   → 바로, 한번 기록(저장)해놓으면 프로그램이 종료될 때까지 지우지 않는다는 점

 

- 따라서,

   메소드 영역에 올라가는 정보들은 "한번 기록이 되면(=메소드 영역에 올리면) 프로그램이 종료될 때까지 유지된다"는 특징을 가지며

   그런 특징을 가져야하는 것들이 메소드 영역에 올라갈 수 있음

   → JVM이 메소드 영역에 올리는 것임

 

3. 스택 영역

- 스택 영역은 잠깐 저장되어야 하는 것들이 담겨 있음

   → 한마디로 정리하자면 [임시저장]을 위한 공간

- 지역변수, 매개변수가 스택 영역에 올라감

 

- 스택 영역에 저장된 변수들은 (해당 변수가 선언된) 메소드가 종료될 때 스택 영역에서 소멸됨

 

4. 힙 영역

- 힙 영역은 인스턴스를 저장하기 위한 영역임

 

- 위에서 변수는 스택  영역에 저장된다고 했음

   → 그렇다면 [참조변수]와 [인스턴스]를 그림으로 표현해보면 아래와 같이 표현될 수 있음

 

- 참조변수 역시 어느 메소드의 지역변수이기 때문에 소멸될 수 있음.

   그렇다면 참조변수가 소멸될 때마다, 힙 영역의 인스턴스도 무조건 지워지는걸까

   → 당연히 아님

   → 일반적으로 참조변수가 사라지면 해당 참조변수가 가리키고 있던 인스턴스에 접근할 수 없음

        * 참조변수를 이용하지 않고 인스턴스에 접근하려면, 인스턴스가 저장된 메모리 주소 등을 알아야 하는데 알기 어려워서

   → 그런 이유로 참조변수가 소멸 될 때, 해당 참조변수가 가리키고 있던 인스턴스도 무조건 함께 지워질 것 같다고 생각할 수 있지만

        그렇지 않음

   → 그 이유는 아래와 같은 상황 때문

 

- A 라는 인스턴스를 참조변수 str1과 str2가 가리키고 있다고 가정하자

   → 이때 str1 변수가 스택 영역에서 소멸되었다고 가정하자

   → str1이 소멸되면서 그 참조변수가 가리키고 있던 A 인스턴스까지 함께 소멸 되어버리면

        str2는 참조할 대상(=A 인스턴스)이 사라지게 되고 문제가 생김

   → 때문에 참조변수가 스택 영역에서 소멸되었어도 그 참조변수가 가리키고 있던 인스턴스까지 반드시 지워지지는 않음

   → 또한 이게 "인스턴스를 스택 영역에 (변수와 함께) 저장하지 않고 별도로 힙 영역에서 관리하는 이유"이기도 함

         * 지역변수 등과 함께 지워버리지 않고 신중하게 지우기 위해서

 

- 그렇다면 힙 영역에 있는 인스턴스는 어떤 상황에 지워질까(소멸될까)

   → 프로그래머가 수동으로 힙 영역에서 지워줄 필요는 없고

   → 해당 인스턴스를 참조하는 참조변수가 하나도 없게 되면 JVM이 자동으로 힙 영역에서 지워줌

   → 이를 가비지 컬렉션(쓰레기 수집)이라고 함

         * 아무도 참조하지 않는 인스턴스가 '가비지(쓰레기)'가 되는거고

         * 그걸 모아서 버려주는게 JVM이 해주는 일 중 하나

 

- 결국 인스턴스를 힙 영역에 별도로 나눠 관리하는 이유는

   지역변수(참조변수)를 지우면서 인스턴스도 함께 지웠다간 큰 문제가 생길 수 있으니

   신중하게 관리하기 위해서임

 

 

# 가비지 컬렉션?

- 메모리 관리 기법 중 하나

- 프로그램이 동적으로 할당했던 메모리 영역 중에서 필요없게 된 영역을 해제하는 기능

 

- 자바스크립트(JavaScript) 같은 경우 "자바스크립트 엔진 내에선 가비지 컬렉터가 끊임없이 동작하며 모든 객체를 모니터링하고, 도달할 수 없는 객체는 삭제한다"고 함

(참고 자료 : https://ko.javascript.info/garbage-collection)

 

- 그렇다면 Java에서는 JVM(가비지 컬렉터)이 끊임없이 힙 영역을 모니터링하면서 불필요한 인스턴스를 삭제할 것으로 유추됨

- 자세한 사항은 구글과 (신뢰도는 좀 떨어지지만) 위키백과를 참고

 

출처 :

https://ko.wikipedia.org/wiki/%EC%93%B0%EB%A0%88%EA%B8%B0_%EC%88%98%EC%A7%91_(%EC%BB%B4%ED%93%A8%ED%84%B0_%EA%B3%BC%ED%95%99)

 

Comments