JVM(Java Virtual Machine, 자바 가상 머신)은 Java의 Bytecode를 해석하고 실행하는 역할을 한다.
- JVM만 설치하면 운영체제(OS)에 관계 없이 java파일을 실행시킬 수 있다.

변수는 크게 네 종류로, 변수의 선언된 위치에 따라 클래스변수, 인스턴스변수, 지역변수, 매개변수로 나뉜다.
public class Variable {
public static int age = 20; // 클래스 변수 (전역 변수)
int height = 60; // 인스턴스 변수 (전역 변수)
public static void main(String[] args) { // 매개변수 (파라미터)
int size = 50; // 지역 변수
}ㅍ
}

클래스 변수(Static 변수), 생성자(Constructor), 메소드(Method), Class의 정보 등을 저장하는 공간
Class가 로딩될 때 생성된다.메소드 내에서 정의하는 기본 자료형(primitive Type)에 해당하는 지역변수의 데이터 값이 저장되는 공간
• int, double, byte, long, boolean 등
스택 프레임이 생기고, 그 안에 메소드를 호출❓ 스택 프레임(stack frame)
: 하나의 메서드에 필요한 메모리 덩어리를 묶어서 스택 프레임(Stack Frame)이라고 한다.
메서드의 매개변수, 지역 변수, 리턴값 등이 있다.인스턴스(객체), 배열 등 참조형(Reference Type) 데이터 객체의 실제 데이터가 저장되는 공간이다.
• String, array, enum, class, interface, Object 등
new 키워드로 인스턴스를 생성할 때 Heap 영역에는 생성된 객체가 저장되고, Stack 영역에는 생성된 객체에 대한 주소 값(Reference)이 저장된다.
→ Heap 영역에 있는 데이터를 가리키는 레퍼런스 변수는 Stack에 저장된다.
```java
public class Main {
public static int s = 10;
public static void main(String[] args) {
int a = 5;
int b = 5;
int result1 = a + b + Main.s;
System.out.println(result1); // 20
Counter sub = new Counter();
twice(sub);
int result2 = sub.get();
System.out.println(result2); // 100
}
public static void twice(Counter c) {
c.plus(10);
c.plus(20);
}
}
class Counter {
public int state = 50;
public final int count = 20;
public int get() {
return state + count;
}
public void plus(int n) {
state += n;
}
}
```

클래스 변수(static)와 메소드(method)는 무조건 Method 영역에 적재된다.
💡 이때 일반 인스턴스 변수인 Counter 클래스의 변수
state와count는 final 키워드가 붙었지만, 클래스 변수(static)나 메소드(method)가 아니므로 메서드 영역에 들어가지 않는다.

Class Main의 메인 메서드(public static void main(String[] agrs)가 실행되면 스택 영역에 스택 프레임이 쌓이고 지역 변수와 매개 변수가 담긴다.

생성자 new Counter()를 호출하면 Heap 영역에 Counter 클래스 인스턴스 변수들이 저장된다.
그리고 Stack 영역의 지역변수 sub에 주소값으로 연결되게 된다.

twice(sub) 메소드를 실행하면 Stack 영역에 새로운 스택 프레임이 쌓인다.
Arguments로 클래스를 전달했기 때문에 twice()의 매개 변수 c는 주소값으로 같은 힙 영역을 가리키게 된다.

plus() 메소드를 호출해 실행하면 → 메소드이기 때문에 Stack 영역에 새로운 스택 프레임이 생성된다.this 라는 암묵적인 변수가 자동 생성되게 되는데, 이 this 변수는 자동으로 Heap 영역에 있는 Counter 객체를 가리키게 된다.plus() 메소드 안의 코드 state += n 가 동작하면서 Heap 영역에 있는 인스턴스 변수 state 의 값이 변하게 된다.

❶ 실행 후 종료된 plus()스택 프레임은 Stack 영역에서 제거된다.
❷ 그 후 sub 객체 변수의 메소드인 get() 을 호출하면 Stack 영역에 새로운 스택 프레임이 생기고, this 변수가 Heap 영역의 객체를 가리키게 된다. 그리고 Heap 영역의 변수를 반환한다.
❸ 실행이 종료된 get() 스택 프레임이 Stack 영역에서 제거되고, main 스택 프레임에 result2 지역 변수가 추가된다.
💡 TIP!
호출되는 메서드가 파라미터로 객체값을 전달받아 객체의 상태를 변경하게 되면, 메서드 종료(스택 제거) 이후에도 Heap 영역에 있는 객체의 상태는 쭉 유지된다.

Stack 영역은 메서드의 끝을 알려주는 닫는 중괄호( } )를 만나면 자동으로 메모리에서 제거된다.
❗️그러나 Heap 영역에는 여전히 객체 데이터가 메모리에 남아있다.

코드 실행이 모두 끝나면 Method(Static)영역이 비워진다.
❗️ 가비지 컬렉터(GC)는 Heap 영역에 남아있는 더 이상 참조되지 않는 객체를 식별해 청소하는 역할을 한다.

변수 name은 Stack 영역에 저장되며, 해당 변수의 주소는 Heap 영역에 저장되어 ‘Mark’를 가리킨다.

힙 메모리는 애플리케이션의 모든 부분에서 사용되며, 반면에 스택 메모리는 하나의 스레드가 실행될 때 사용
→ 따라서 힙 과 메서드 공간에 저장된 객체는 어디서든지 접근이 가능하지만, 스택 메모리는 다른 스레드가 접근할 수 없다.
언제든지 객체가 생성되면 항상 힙 공간에 저장되며, 스택 메모리는 힙 공간에 있는 객체를 참조만 한다.
→ 즉, 스택 메모리는 primitive 타입의 지역변수와 힙 공간에 있는 객체 참조 변수만 갖고 있다.
스택메모리의 생명주기는 매우 짧으며, 힙 메모리는 애플리케이션의 시작부터 끝까지 살아남는다.
자바 코드를 실행할때 따로 -Xms과 -Xmx 옵션을 사용하면 힙 메모리의 초기 사이즈와 최대 사이즈를 조절할 수 있다.
스택 메모리가 가득차면 자바에서는 java.lang.StackOverFlowError를 발생하고, 힙 메모리가 가득차면 java.lang.OutOfMemoryError : Java Heap Space에러를 발생
스택 메모리 사이즈는 힙 메모리와 비교했을 때 매우 적다. 하지만 스택 메모리는 간단한 메모리 할당 방법(LIFO)를 사용하므로 힙 메모리보다 빠르다.