자바가 실행되는 과정
1. JDK, JRE, JVM의 역할과 장점
JDK로 개발된 프로그램은 JRE에 의해 실행되고 가상 기계인 JVM 환경에서 구동됩니다.
JDK는 소스 코드를 바이트코드로 바꿔줄 수 있는 javac.exe파일을 갖고 있습니다.
JRE는 자바 프로그램을 실행할 수 있는 java.exe파일을 갖고 있습니다.
이런 구조는 컴퓨터 종류 및 OS가 서로 다르더라도 하나의 컴파일러로 실행할 수 있다는 장점이 됩니다.
JDK, JRE, JVM이란 용어가 처음엔 무척 생소합니다.
JDK는 자바 개발 도구로 Java Development Kit의 약자입니다.
JRE는 자바 실행 환경으로 Java Runtime Environment의 약자입니다.
JVM은 자바를 실행하는 가상 머신으로 Java Virutal Machine의 약자입니다.
언어의 작동 원리를 이해하는 것은 꽤 중요한 문제라고 느껴지네요. 👏👏
2. JAVA 프로그램 작동 순서
JRE의 역할은 JVM을 부팅하는 것이고, JVM의 역할은 다음과 같습니다.
1. Static 공간에 java.lang 및 import한 패키지들을 Load합니다.
2. 소스 코드에 존재하는 모든 클래스들을 Static 공간에 Load합니다.
3. main() 메서드 유무를 확인한 뒤 스택 공간에 스택 프레임을 할당합니다.
4. main() 메서드 안의 지역변수들을 배치합니다.
main() 메서드의 스택 프레임이 사라지면 JRE는 JVM을 종료하고 JRE도 메모리에서 사라집니다.
간단한 main() 메서드를 실행하는 데에도 JRE와 JVM은 바쁘게 작동한다는 것을 깨달았습니다.
3. 지역변수와 공유변수
메모리 공간은 크게 코드 공간, 데이터 공간 안에서도 Static, Stack, Heap 공간으로 나뉘었습니다.
메모리는 그냥 하나의 메모리인 줄 알았는데 신기하네요. 👀
각 메모리별 할당되는 변수의 종류에 대해 알아보았습니다.
Static 공간에는 클래스 멤버 변수가 할당되고 JVM 종료시까지 존재합니다.
Stack 공간에 존재하는 변수는 메서드 내에 있는 지역 변수입니다. 스택 프레임이 사라지면 함께 소멸되죠. 🤷♂️
Heap 공간에는 객체 멤버 변수가 할당되고, 객체가 가비지 컬렉터에게 수거되면 소멸됩니다.
Static 공간 변수는 전역 변수, Stack 공간 변수는 지역 변수로 볼 수 있습니다.
Stack 공간 안에서도 여러 메소드들이 존재할 수 있습니다.
하지만 이 메서드들 간 지역 변수 직접 접근은 불가능합니다.
이를 위해서는 메서드 인자를 전달해주거나 리턴값을 반환해서 사용해야 합니다.
스택 외부 프레임에서 내부 프레임으로 접근은 불가능하나, 내부 프레임에서 외부 프레임으로는 접근 가능한 것과 유사한 원리라고 생각됩니다.
Method1과 Method2는 서로의 지역변수 k에 대해 직접 참조할 수 없으며 두 메서드의 k는 서로 다른 변수 공간입니다.
직접 참조할 수 없기 때문에 메서드 인자 전달이나 리턴값을 사용합니다.
다른 이유는 자바에서는 포인터가 없기 때문인 것도 있습니다.
각 변수의 정확한 위치를 알 수 없기 때문이죠. 🤦♂️
그래서 변수에 들어 있는 값 Value만을 전달해서 소통합니다.
이게 Call By Value방식이라고 부르는 이유인가봅니다.
반면 전역 변수는 Static 영역에 할당되어, 각 메서드 내에서도 참조가 가능합니다.
지역 변수는 스택 프레임에 종속되며 전역 변수는 스태틱 공간에 할당되므로 독립적입니다.
언뜻 보기엔 좋아보이지만 이건 큰 문제를 발생시킬 우려가 있습니다.
대표적으로 멀티 스레드를 사용하는 프로그램에서 그렇습니다.
불가피하게 전역 변수를 사용할 경우 스레드별로 Lock을 걸어 사용해야 하는 경우입니다.
전역 변수 사용은 지양하는 것이 좋습니다.
꼭 사용해야 한다면 읽기 전용으로 값을 공유하여 전역 상수로 쓸 것을 권장합니다.
이렇게 지역 변수와 공유 변수에 대해 정리해 보았습니다.
4. [지식in]가비지 컬렉터
kin.naver.com/qna/detail.nhn?d1id=1&dirId=104&docId=376891428&page=1#answer2
객체지향 프로그래밍에서 전역 변수와 지역 변수의 개념은 언어마다 동일합니다.
메서드(함수) 내에 선언된 변수는 모두 지역변수입니다.
파이썬의 경우 인터프리터 언어이므로 메서드 밖에 선언된 변수는 전역변수라고 할 수 있습니다.
클래스 안에 있는 변수도 전역 변수(=클래스 멤버 변수, 필드, 속성, Property)입니다.
그럼 파이썬의 경우 메모리를 더 많이 사용할까요? 🤔
꼭 그렇지는 않습니다.
우선 C와 파이썬,자바와 같은 객체지향 언어 사이에는 메모리 관리방식에서 큰 차이가 납니다.
C의 경우 포인터를 통해 직접 메모리에 접근이 가능합니다.
반면 파이썬, 자바와 같은 경우 포인터가 없으므로 프로그래머는 메모리 관리를 할 수 없습니다.
따라서 가비지 컬렉터(Garbage Collector)가 존재합니다.
코드상 참조되지 않는 객체나 변수들(Garbage)을 자동으로 수거해갑니다.
파이썬의 경우, 가비지 컬렉터의 종류로 레퍼런스 카운터라는 것과 함께 작동합니다.
객체 or 변수가 몇 번 참조되었는지를 Count하는 함수로 참조 횟수가 0이면 수거해가는 것이죠.
하지만 레퍼런스 카운터라는 것만으로는 메모리 누수가 발생할 수 있습니다.
계속해서 자기 자신을 참조하는 객체는 수거할 수 없는 상황입니다.
따라서 가비지 컬렉터를 추가로 사용하는 것입니다.
References
김종민 저, 스프링 입문을 위한 자바 객체 지향의 원리와 이해
'객체 지향 프로그래밍 > Java' 카테고리의 다른 글
스레드 - 멀티 스레드와 멀티 프로세스 쉽게 구분하기 (3) | 2020.12.27 |
---|---|
메모리 구조 - 스태틱, 스택, 힙 영역 (0) | 2020.12.22 |