자바 메모리 구조는 크게 메서드영역, 스택영역, 힙 영역으로 나눌 수 있다.
- 메서드영역 : 클래스정보를 보관한다. 예를 들면 붕어빵 만드는 틀이라고 생각하면 된다.
- 스택영역: 실제 프로그램이 실행되는 영역이다. 메서드를 실행할때 마다 하나씩 쌓인다.
- 힙 영역: 객체(인스턴스)가 생성되는 영역이다. new 명령어를 사용하면 이 영역을 사용한다. 예를 들면 붕어빵 틀로부터 생성된 붕어빵이 존재하는 공간이다.
- 메서드 영역: 메서드 영역은 프로그램을 실행하는데 필요한 공통 데이터를 관리를 한다. 이 영역은 프로그램의 모든 영역에서 공유한다.
- 클래스정보: 클래스의 실행 코드, 필드, 메서드와 생성자 코드 등 모든 실행 코드가 존재한다.
- Static 영역: static변수들을 보관한다.
- 런타임 상수 풀: 프로그램을 실행하는데 필요한 공통 리터럴 상수를 보관한다. 자바에서 최적화하는 용도로 사용된다.
예를들어 "hello" 라는 리터럴 문자가 있으면 이런 문자를 공통으로 묶어서 관리한다.
- 스택영역: 자바 실행 시, 하나의 실행 스택이 생성된다. 처음에는 main 메서드가 생성되고, 그 위에 다른 메서드들이 생성된다.
각 스택 프레임은 지역 변수, 중간 연산결과, 메서드 호출 정보등을 포함한다.- 스택 프레임: 스택 영역에 쌓이는 네모 박스가 하나의 스택 프레임이다. 메서드를 호출할 때 마다 하나의 스택 프레임이 쌓이고, 메서드가 종료되면 해당 스택 프레임이 제거된다.
- 힙 영역: 객체(인스턴스) 와 배열이 생성되는 영역이다. 가비지 컬렉션(GC)이 이루워지는 주요 영역이며, 더 이상 참조되지 않는 객체는 가비지 컬랙션(GC)에 의해 제거된다.
GC : 참조가 모두 사라진 인스턴스를 메모리 영역에서 삭제한다. 인스턴스끼리 서로 참조하는 경우에도 GC의 대상이 된다.
자바에서 100개의 인스턴스를 생성하고 각각의 변수를 가지는데 변수값을 같더라도, 동일한 메서드에 대한 메모리는 할당하지 않는다.
예를 들어,
public String getName() {
return name;
//장바구니 상품 출력
//각각 상품별 합계가 필요하다.
}
public int getTotalPrice() {
return price * amount;
}
위와 같이 메서드가 두 개가 있는데 name 변수가 100개 있으면 메서드도 메모리에 100개 할당해야 할까?
그러면 자원 낭비가 너무 심하기 때문에 메서드 영역에서 메서드를 불러와서 변수를 대입해서 실행하는 것이다.
스택 과 큐 자료 구조
스택 구조
1번, 2번, 3번 같은 블럭이있다고 가정한다.
마지막에 넣은 것을 먼저 나오는 것을 "후입 선출(LIFO)" 라고 한다.
반대로 마지막에 넣은 것을 마지막에 나오는 것을 "선입 후출(FIFO)"라고 한다.
이는 "큐" 에서 사용 한다.
큐 자료 구조
위 아래가 뚫려 있어서, 먼저 들어간 것이 먼저 나오게 된다.
이러한 자료 구조는 각자 필요한 영역이 있는데, 선착순 이벤트를 하는데 고객이 대기해야 한다면 큐 자료 구조를 사용해야 한다.
스택 영역 활용
다음 코드를 실행하면 스택 영역에서 어떤 변화가 있는지 확인해보자.
package memory;
public class JavaMemoryMain1 {
public static void main(String[] args) {
System.out.println("main start");
method1(10);
System.out.println("main end");
}
static void method1(int m1) {
System.out.println("method1 start");
int cal = m1 * 2;
method2(cal);
System.out.println("method1 end");
}
static void method2(int m2) {
System.out.println("method2 start");
System.out.println("method2 end");
} }
}
main start
method1 start
method2 start
method2 end
method1 end
main end
위와 같은 결과가 나온다.
Main 메서드가 가장먼저 실행이 되었으나, 마지막 main end 는 마지막에 호출된 것을 알 수 있다.
처음에는 Main()을 실행되었으나, method1, method2 가 각각 들어오게 된다.
그렇다면 종료되었을 때는?
마지막에 들어온 메서드가 먼저 종료되는 것을 볼 수 있다.
**정리**
자바는 스택 영역을 사용해서 메서드 호출과 지역 변수(매개변수 포함)를 관리한다. 메서드를 계속 호출하면 스택 프레임이 계속 쌓인다.
지역 변수(매개변수 포함)는 스택 영역에서 관리한다.
스택 프레임이 종료되면 지역 변수도 함께 제거된다.
스택 프레임이 모두 제거되면 프로그램도 종료된다.
스택 영역과 힙 영역
그렇다면 스택 영역과 힙 영역이 함께 사용되는 경우를 알아보자.
Main
package memory;
public class JavaMemoryMain2 {
public static void main(String[] args) {
System.out.println("Java Memory Test start");
method1();
System.out.println("Java Memory Test end");
}
static void method1() {
System.out.println("Java Memory method 1 test start");
Data data1 = new Data(10);
method2(data1);
System.out.println("Java Memory method 1 test end");
}
static void method2(Data data2) {
System.out.println("Java Memory method 2 test start");
System.out.println("data.value=" + data2.getValue());
System.out.println("Java Memory method 2 test end");
}
}
Data
package memory;
public class Data {
private int value;
public Data(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
실행 결과
Java Memory Test start
Java Memory method 1 test start
Java Memory method 2 test start
data.value=10
Java Memory method 2 test end
Java Memory method 1 test end
Java Memory Test end
1. Main 영역에 method01, method02 가 생성되었다.
2.Main 영역에서 Metho01 을 먼저 수행하여 스택 프레임이 생성되었다.
3. Method01 은 data(10) 을 참조로 가지고 있는다. 이의 참조값을 힙영역에 저장 한다.
4. Method02을 호출하면서 data(10)에 대한 영역을 02에서도 참조할 수 있게 한다.
5. Method02가 종료되면서 사라진다.
6. Method01이 종료되면서 사라진다. 이에 지역 변수인 data10도 같이 사라진다.
7. 이제 `x001` 참조값을 가진 `Data` 인스턴스를 참조하는 곳이 더는 없다.
참조하는 곳이 없으므로 사용되는 곳도 없다. 결과적으로 프로그램에서 더는 사용하지 않는 객체인 것이다. 이런 객체는 메모리만 차지하게 된다. GC(가비지 컬렉션)은 이렇게 참조가 모두 사라진 인스턴스를 찾아서 메모리에서 제거한다.
정리
지역 변수는 스택 영역에, 객체(인스턴스)는 힙 영역에 관리되는 것을 확인했다. 이제 나머지 하나가 남았다. 바로 메서드 영역이다. 메서드 영역이 관리하는 변수도 있다. 이것을 이해하기 위해서는 먼저 `static` 키워드를 알아야 한다.
`static` 키워드는 메서드 영역과 밀접한 연관이 있다.
'JAVA' 카테고리의 다른 글
[Java] Static 메서드1 (1) | 2024.10.27 |
---|---|
[Java] Static (0) | 2024.10.27 |
[Java] 캡슐화 (1) | 2024.10.27 |
[Java] 생성자 (0) | 2024.10.23 |
[Java] 생성자 (0) | 2024.10.20 |