메인 메소드 블록
자바 프로그램을 실행하면 자바 가상머신은 클래스내에 포함되어 있는 메인 메소드를 찾아 실행한다.
public static void main(String[] args){...}
- public : 모든 클래스에서도 해당 변수나 메서드가 접근이 가능하다는 의미로 프로그램의 시작은 main 이기 때문에 다른 곳에서도 호출할 수 있도록 public을 사용
- static : 자바가 compile이 되는 순간 가장 빠르게 정의되어 별도의 객체 생성 없이 모든 객체와 공유가 가능
- void : 별도로 return 값 없이 메소드를 실행하고 끝난다는 의미.
- main : 이 메서드가 main 메서드라는 의미
메인 메소드 블록에서 왜 static 이어야 할까
JVM은 example() 메소드에 접근하기 전에 인스턴스를 생성(new) 해야 한다. 메서드를 가지고 있는 객체의 참조를 모르고서 그 메서드에 접근할 방법이 없기 때문이다.
main() 도 마찬가지다. 만약 main() 메소드가 static이 아니라면 접근전에 인스턴스를 생성(new) 해야한다.
하지만 static 선언 함으로써, main 메소드는 JVM을 실행할 때 메모리(Method Area)에 올라가기 때문에 바로 접근해서 사용하며 그만이다.
💡 그렇다면 JVM 왜 example() 메소드에 접근하기 전에 인스턴스를 생성(new) 해야 할까??
JVM의 구조와 동작 방식을 공부해야 할 것 같다.
Non-static 메소드는 클래스의 인스턴스를 생성한 후 해당 인스턴스를 통해 호출할 수 있다.
바로 호출 할 수 없고 인스턴스를 생성한 후 해당 인스턴스를 통해 호출하는 이유는 무엇 일까?
객체 지향 프로그래밍의 개념과 원칙을 따르기 위해?
JVM의 구조
클래스 로더의 구조
- 바이트 코드(.class)들을 엮어서 JVM의 메모리 영역인 Runtime Data Area에 배치 한다.
- 필요한 경우 마다 동적으로 메모리에 적재한다.
실행 엔진의 동작
런타임 데이터 영역에 배치된 바이트 코드를 명령어 단위로 읽어서 실행한다.
위의 동작을 수행하기 위해 인터프리터와 JIT 컴파일러 두가지 방식을 혼합하여 바이트코드를 실행한다.
인터프리터 : 한줄씩 해석 → 수행
JIT컴파일러 : 더 많은양을 해석후 몰아서 수행
각각의 장단점이 있다. 생각해보면 당연함.
가비지 컬렉터
가비지 컬렉터에 대한 이미지 이지만, 객체를 생성해서 메소드를 호출하는 것을 이그림으로 설명 할 수 있을것 같다.
런타임 데이터 영역
JVM의 메모리 영역 입니다.
매서드 영역은 클래스 영역이나 스태틱 영역으로도 불립니다.
Method(Static) 영역
간단히 말하면, 메서드 영역에는 정적 필드와 클래스 구조만 갖고 있다고 할수있다.
중간 정리
기본적으로, 자바 프로그램을 실행하면 JVM은 클래스내에 포함되어 있는 메인 메소드를 찾아 실행한다.
자바 프로그램을 실행하면 JVM의 클래스 로더는 바이트코드(.class)를 로드 하는데, 메소드 영역으로 로드 한다.
그리고, 로드한 데이터를 클래스 별로 적재하는데 클래스의 정적 필드와 정적 메소드도 적재된다.
따라서, 클래스가 메모리로 로딩되면 정적 멤버를 바로 사용할 수 있다.
결과적으로 JVM은 정적 멤버인 static main 메소드를 바로 실행할 수 있게 되는것 이다.
더 생각해볼 것
정적 메소드는 클래스가 로딩될때 메모리에 올라간다는걸 알았다. 그러면,
일반적인 메소드는 언제 어떻게 메모리에 올라갈까 ?
Class class = new Class(); 는 어떻게 동작하나.
힙 영역 (Heap Area)
여기에 그놈에 객체를 만든다.
객체가 생성된다. 힙영역에 저장된다. 스택영역에 변수가 생성되고 변수에 힙영역에있는 객체의 주소가 저장된다.
스택영역 (Stack Area)
기본 자료형을 생성할 때 저장하는 공간으로, 임시적으로 사용되는 변수나 정보들이 저장되는 영역이다.
메소드 호출시 마다 각각의 스택프레임(그 메서드만을 위한 공간) 이 생성되고, 메소드 안에서 사용되는 값들을 저장하고, 호출된 메서드의 매개변수, 지역변수, 리턴값 및 연산 시 일어나는 값들을 임시로 저장한다.
그리고 메서드 수행 끝나면 프레임별로 삭제됨
😂😂😂😂😂 궁금했던 부분이다 ~
또 중간 정리
PC 레지스터 (Program Counter Register)
런타임 데이터영역에 존재. 현재 수행중인 JVM 명령어 주소를 저장하는 공간.(다음명령어의 주소도)
PC 레지스터는 현재 실행 중인 명령어의 주소를 가리키고, 다음에 실행할 명령어의 주소를 저장합니다. 이를 통해 프로세서는 명령어를 순차적으로 실행할 수 있습니다. PC 레지스터를 사용하여 명령어의 흐름을 추적하면서 프로그램의 실행 흐름을 제어할 수 있습니다.
우선, 일반적으로 프로그램의 실행은 CPU에서 명령어를 수행하는 과정에서 이루어짐.
이때 CPU가 연산하는데 필요한 정보를 레지스터에 저장한다.
자바에서 PC Register 는 일반적인것과는 다르다, 자바는 CPU에 직접 연산을 수행하도록 하지 않고
현재 작업하는 내용을 CPU에게 연산으로 제공해야 하며, 이를 위한 버퍼 공간으로 PC Register라는 메모리 영역을 만들게 된 것이다.
따라서 JVM은 스택에서 비연산값 Operand를 뽑아 별도의 메모리 공간인 PC Register에 저장하는 방식을 취한다. (Operand = 피연산자)
만약에 스레드가 자바 메소드를 수행하고 있으면 JVM 명령(JVM명령이란 바이트코드로 된 명령어 세트)의 주소를 PC Register에 저장한다.
그러다 자바가 아닌 다른 언어의 메소드를 수행하고 있다면 , undefined상태가 된다.
PC 레지스터는 각 쓰레드 마다 하나씩 있다
JVM 명령어 자체는 메서드 영역에 저장되고, 스택 프레임은 실행 중인 메서드의 데이터를 저장하는 데 사용됩니다. 명령어의 주소는 메서드 영역에 저장된 해당 메서드의 코드의 시작 위치와 오프셋으로 계산됩니다.
Native method stack
네이티브 매서드 스택은 자바 코드가 컴파일되어 생성되는 바이트 코드가 아닌 실제 실행할 수 있는 기계어로 작성된 프로그램을 실행 시키는 영역이다.
또한, 자바 이외의 언어로 작성된 네이티브 코드를 실행하기 위한 공간이다.
Java API는 Native 메소드를 통해 OS 자원과 연계되어 있다.
(Java <<< JavaAPI(Navtive메소드 활용 >>> OS자원)
만약 java.io.InputStream 이라는 클래스를 사용하여 특정 파일 시스템의 정보를 읽어 온다고 가정하면 Java는 Class 파일 내에 있는 java.io.InputStream의 Symbolic Reference를 이용하여 Runtime 시 해당 Instance에 접근하게 된다. 그러면 이 Instance에 대한 내용, 즉 실제 File에 대한 접근은 Native Method를 통해 OS에 명령을 전달하게 된다. 이후 OS는 실제 File IO를 일으키게 되고, 이 File IO의 결과는 다시 Native Method를 통해 Java API로 전달되는 과정을 거쳐 프로그램이 실행된다. 이러한 Java API를 포함하는 JRE는 OS나 머신에 따라 적절한 것을 설치하면 java 프로그램에게는 플렛폼의 제약을 떠나 동일한 실행환경을 제공하게 된다.
Java Native Interface
Native Method Libraray
런타임 데이터 Area의 쓰레드(나중에)
'JAVA' 카테고리의 다른 글
[JAVA] 객체지향 복습 Quiz (0) | 2023.06.20 |
---|---|
[JAVA] 객체지향 복습 (0) | 2023.06.20 |
[Java] 자료형 / 형변환 복습 (2) | 2023.06.18 |
[Java] 소스코드 형태 복습 (0) | 2023.06.18 |