1. JVM의 동작 순서
1. 자바를 실행 시키면 자바 컴파일러에 의해 자바(. java) 파일이 클래스 파일(. class)로 컴파일된다.
2. 이후에 클래스 로더에 .class 파일(바이트 코드)을 로드한다.
- 이 과정에서 클래스 파일은 메모리에 저장되고 파일 정보가 JVM내부에 유지된다.
3. class loder를 통해 JVM Runtime Data Area(메모리 영역)을 구성한다. (메소드 영역, 힙영역, 스택영역)
-> 아래에 나오지만 간단하게 설명하면
- 1. 메소드 영역 : 클래스 수준의 정보(클래스 이름, 부모 클래스 이름, 메소드, 변수)
- 2. 힙 영역 :객체, 배열이 생성되는 영역 (new 생성자로 생성되는)
- 3. 스택 영역 : 각 스레드 마나 하나씩 존재, 메소드 호출 시 마다 프레임 단위로 추가하고 삭제
- 4. PCB, Natvie Method stack
4. 실행엔진에 의해 실행된다.
- 인터프리터가 바이트 코드를 한 줄 씩 읽어서 해석하여 기계어로 번역된다. ➡️ 자바는 컴파일러와 인터프리터의 두 가지 방식을 병행해서 사용하는 언어이다.
➡️ 하지만 매번 컴파일을 통해 Java파일을 Byte code로 변환하고 다시 인터프리터에서 한 줄씩 읽어 기계어로 변환하는 작업은 비효율적이었다. 이를 해결하기 위해 JIT 컴파일러가 생성 되었다.
- JIT 컴파일러 : 인터프리터의 성능을 개선하기 위해 반복되는 코드를 네이티브 코드로 컴파일 해서 실행하여 기존에 인터프리터 보다 빠른 실행 속도를 제공한다.
- GC에 의해 사용되지 않는 메모리를 관리한다.
5. 네이티브 메서드를 호출하여 동작한다. (자바 언어로 실행되지 않는 라이브러리를 사용하면 JNI(java native interface)를 통해 c, c++로 작성된 코드를 호출하여 사용한다.)
메인 메서드를 실행시키면 메인 스레드가 동작을 시작한다.
각 스레드는 각각의 스택 영역, PC 레지스터, 네이티브 메서드 스택영역을 가진다. (힙, 메서드 : 모든 스레드가 공유)
2. 자바의 3가지 변수 타입
자바의 변수는 클래스 변수, 인스턴스 변수, 지역변수(매개변수)로 나뉜다.
클래스 영역에서의 변수
클래스 변수(static 변수)
- 클래스 영역에서 static 이 붙는 변수로 여러 객체에서 공통으로 사용하고 싶은 경우 사용가능하다.
- 객체를 로딩하는 시점에 생성되어서 객체 생성을 하지 않아도 사용할 수 있다.
인스턴스 변수
- 클래스 영역에서 static이 아닌 변수(new 키워드로 선언된 변수, 각 객체마다 고유값을 가진 변수)
- 객체를 생성해야만 사용할 수 있다.
메서드 영역에서의 변수
지역변수(매개변수 포함)
- 메서드 내에서 선언된 변수 (메서드 수행 끝나면 소멸)
자바는 실행시에 먼저 static 변수들을 클래스가 로딩되는 시점에 생성한다.
그 후에 클래스 인스턴스(객체)가 생성되면 인스턴스 변수가 생성되고, 메서드가 실행되면 메서드 변수가 실행된다.
3. 자바의 메모리 영역
1) Method Area
Runtime constants poll (상수 풀) : 클래스, 인터페이스, 메서드 등에서 사용되는 상수 값을 저장한다. JVM 로드할때 생성되며 각 클래스, 인터페이스에서 사용하는 상수 값을 저장한다.
- 각각의 상수값은 해당하는 타입의 값을 저장하며 해당하는 값에 대한 참조를 가지고 있다.
- 상수풀의 크기는 컴파일 시에 결정되며, 런타임 중에 변경되지 않는다.
Class Information : 클래스 정보를 가진다. ( 클래스 이름, 부모 클래스 ,인터페이스, 메서드, 변수등의 정보를 저장한다.)
- 클래스 정보를 클래스 로딩 시에 생성된다.
Static Variables :
- 클래스의 모든 인스턴스가 공유하는 변수이다.
- 클래스 로딩 시점에 생성되고 메모리의 데이터 영역에 저장된다.
- 자바 클래스 파일의 바이트 코드, 상수풀( constants poll - immutable, final로 선언된 static 변수), 클래스 변수, static 변수, 메소드 코드 등이 저장된다.
- JVM이 실행되면서 클래스 파일들이 로딩되고 메서드 영역에 저장된다.
- 메서드 영역을 모든 스레드가 공유하는 공간이어서 멀티 스레드 환경에서 동기화 문제가 발생할 수 있다.
- 메서드 영역은 static, final, 생성자와 같은 것을 저장하여 프로그램의 시작부터 끝까지 메모리에 남아 있고 언제든 사용이 가능하다
- 클래스가 메모리에 로딩될때 생성된다. 객체를 생성하지 않아도 사용가능하다.
2) Heap(GC 의 대상)
- 인스턴스 변수(객체, 배열)가 저장된다. (객체 소멸 시점까지 저장된다)
- new 연산자를 이용하여 객체를 동적으로 생성할때 사용되는 영역
- 크기가 유동적이고 메모리 할당과 해제가 빈번하여 속도는 느리지만 많은 양의 데이터를 저장할 수 있다
+) string에 대해서 -> https://jinseongsoft.tistory.com/365 (스트링이 저장되는 두가지 방법 )
- new String을 하지 않아야 하는 이유 -> heap에 계속 생성된다.
- String Constants Pool에 저장된 값을 사용하면 동일한 String 을 가지고 있다면 같은곳을 가리킨다.
- 상수리터럴이 자바 7버전 이전에서는 상수값 전용 메모리에 (Perm 영역->메소드 데이터 영역 ) 따로 저장되어졌는데, 런타임중 너무 많은 스트링을 사용하면 OutOfMemory(OOM) 예외를 발생시킬 수 있어 Java7 이후로는 Heap 메모리영역에서 관리하며 가비지 컬렉터의 대상이 되었다.
- java8 이후에는 PermGen은 Metaspace로 이름을 변경하였다
- 기본적으로 java string poll은 hashtable구조를 가지고 있다
3) Stack
- 메소드호출시에 해당 메서드를 위한 프레임이 생성된다.
- 메서드가 종료되면 해당 프레임을 제거한다.
- 이때 생성되는 프레임이 스택 영역에 저장되고 지역변수, 매개변수, 메서드 호출의 정보가 저장된다.
- LFIO ( 후입선출) 구조를 가진다.
- 메모리의 크기가 작고 속도가 빨라 빠른 메모라 할당과 해제가 필요한 경우 적합하다.
- stack 영역은 변수가 선언 되었을때 해당 변수가 원시 변수( primitive 타입)이라면 값이 바로 스택에 저장되지만 만약 객체타입, 참조변수 타입(배열, 객체)라면 참조 변수의 값이 저장된 힙의 위치를 스택에 저장하여 사용한다.
4) PC Register(JVM 내부 사용)
- 스레드가 명령어를 실행하기 위해 다음 실행할 명령어의 주소를 저장한다.
5) Native Method Stack(JVM 내부 사용)
- 자바 코드가 아닌 네이티브 코드를 실행할 때 사용되는 스택이다.
참고
https://jinseongsoft.tistory.com/365
https://cornswrold.tistory.com/253
https://www.baeldung.com/java-string-pool#performance-and-optimizations
https://sabarada.tistory.com/137
https://blog.breakingthat.com/2018/12/21/java-constant-pool%EA%B3%BC-string-pool/
'JAVA' 카테고리의 다른 글
Stream 스트림 (0) | 2023.03.19 |
---|---|
람다식(Lambda Expression) (1) | 2023.03.08 |
Enum 클래스 (0) | 2023.02.28 |
ArrayList와 LinkedList (0) | 2023.02.24 |
오버로딩과 오버라이딩 (0) | 2023.02.22 |
댓글