JVM의 메모리 구조
응용프로그램이 실행되면 JVM은 시스템으로부터 프로그램을 수행하는데 필요한 메모리를 할당받고 JJVM은 이 메모리를 용도에 따라 여러 영역으로 나누어 관리한다.
1. 메서드 영역(method area)
프로그램 실행 중 어떤 클래스가 사용되면, JVM은 해당 클래스의 클래스 파일을 읽어서 분석하여 클래스에 대한 정보(클래스 데이터)를 이곳에 저장한다. 이때, 그 클래스의 클래스 변수(class variable)도 이 영역에 함께 생성된다.
2. 힙(heap)
인스턴스가 생성되는 공간, 프로그램 실행 중 생성되는 인스턴스는 모두 이곳에 생성된다.
즉, 인스턴스 변수(instance variable)들이 생성되는 공간이다.
3. 호출스택(call stack 또는 excution stack)
호출 스택은 메서드의 작업에 필요한 메모리 공간을 제공한다. 메서드가 호출되면, 호출 스택에 호출된 메서드를 위한 메모리가 할당되며, 이 메모리는 메서드가 작업을 수행하는 동안 지역변수(매개변수 포함)들과 연산의 중간결과 등을 저장하는 데 사용된다. 그리고 메서드가 작업을 마치면 할당되었던 메모리 공간은 반환되어 비워진다.
- 메서드가 호출되면 수행에 필요한 만큼의 메모리를 스택에 할당받는다.
- 메서드가 수행을 마치고나면 사용했던 메모리를 반환하고 스택에서 제거된다.
- 호출스택의 제일 위에 있는 메서드가 현재 실행 중인 메서드이다.
- 아래에 있는 메서드가 바로 위의 메서드를 호출한 메서드이다.
반환타입(return type)이 있는 메서드는 종료되면서 결괏값을 자신을 호출한 메서드(caller)에게 반환한다.
public class CallStackTest {
public static void main(String[] args) {
firstMethod();
}
static void firstMethod() {
secondMethod();
}
static void secondMethod() {
System.out.println("secondMethod()");
}
}
secondMethod()
1~2. 위의 예제를 실행시키면, JVM에 의해서 main메서드가 호출됨으로써 프로그램이 시작된다. 이때, 호출 스택에는 main메서드를 위한 메모리 공간이 할당되고 main메서드의 코드가 수행되기 시작한다.
3.main메서드에서 firstMethod()를 호출한 상태이다. 아직 main메서드가 끝난 것은 아니므로 main메서드는 호출스택에 대기상태로 남아있고 firstMethod()의 수행이 시작된다.
4. firstMethod()에서 다시 secondeMethod()를 호출했다. firstMethod()는 secondMethod()가 수행을 마칠 때까지 대기상태에 있게 된다. secondMethod()가 수행을 마쳐야 firstMetohd()의 나머지 문장들을 수행할 수 있기 때문이다.
5. secondMethod()에서 println()을 호출했다. println메서드에 의해 secondMethod()가 화면에 출력된다.
6. println메서드의 수행이 완료되어 호출스택에서 사라지고 자신을 호출한 second Method()로 되돌아간다. 대기 중이던 secondMethod()는 println()을 호출한 이후부터 수행을 재개한다.
7. secondMethod()에 더 이상 수행할 코드가 없으므로 종료되고, 자신을 호출한 firstMetohd()로 돌아간다.
8. firstMethod()에 더 이상 수행할 코드가 없으므로 종료되고, 자신을 호출한 main메서드로 돌아간다.
9. main메서드에도 더 이상 수행할 코드가 없으므로 종료되어, 호출 스택은 완전히 비워지게 되고 프로그램은 종료된다.
기본형 매개변수와 참조형 매개변수
자바에서는 메서드를 호출할 때 매개변수로 지정된 값을 메서드의 매개변수에 복사해서 넘겨준다.
매개변수의 타입이 기본형(primitive type)일 때는 기본형 값이 복사되겠지만, 참조형(reference type)이면 인스턴스의 주소가 복사된다.
메서드의 매개변수를 기본형으로 선언하면 단순히 저장된 값만 얻지만, 참조형으로 선언하면 값이 저장된 곳의 주소를 알 수 있기 때문에 값을 읽어 오는 것은 물론 값을 변경하는 것도 가능하다.
기본형 매개변수 변수의 값을 읽기만 할 수 있다.(read only)
참조형 매개변수 변수의 값을 읽고 변경할 수 있다.(read & write)
public class PrimitiveParamEx_1 {
public static void main(String[] args) {
Data d = new Data();
d.x = 10;
System.out.println("main() : x = " + d.x);
change(d.x);
System.out.println("After change(d.x)");
System.out.println("main() : x = " + d.x);
}
static void change(int x) {
x = 1000;
System.out.println("change1() : x = " + x);
}
}
main() : x = 10
change1() : x = 1000
After change(d.x)
main() : x = 10
원본이 아니라 복사본이 변경된 것이라 원본에는 아무런 영향을 미치지 못한다.
public class ReferenceParamEx {
public static void main(String[] args) {
Data d = new Data();
d.x = 10;
System.out.println("main() : x = " + d.x);
}
static void change(Data d) {
d.x = 1000;
System.out.println("change() : x = " + d.x);
}
}
main() : x = 10
change() : x = 1000
After change(x)
main() : x = 1000
public class ReferenceParamEx2 {
public static void main(String[] args) {
int[] x = {10};
System.out.println("main() : x = "+ x[0]);
change(x);
System.out.println("After change(x)");
System.out.println("main() : x = "+ x[0]);
}
static void change(int[] x) {
x[0] = 1000;
System.out.println("change() : x = " +x[0]);
}
}
main() : x = 10
change() : x = 1000
After change(x)
main() : x = 1000
배열이 참조변수를 통해 데이터가 저장된 공간에 접근한다는 것을 배웠는데,
Data클래스의 인스턴스와 길이가 1인 배열을 선언해서 같은 객체를 가르키게 함으로써 값의 변경이 가능해진다.
참조형 반환타입
매개변수뿐만 아니라 반환타입도 참조형이 될 수 있다. 반환타입이 참조형이라는 것은 반환하는 값의 타입이 참조형이라는 얘기인데, 모든 참조형 타입의 값은 객체의 주소이므로 그저 정수값이 반환되는 것일 뿐 특별할 것이 없다.
반환타입이 참조형이라는 것은 메서드가 객체의 주소를 반환한다는 것을 의미한다.
재귀호출(recursive call)
메서드 내부에서 메서드 자신을 호출하는 것을 재귀호출(recursive call)이라 하고, 재귀호출을 하는 메서드를 재귀 메서드라한다.
void method() {
method; //재귀호출. 메서드 자신을 호출한다.
}
대부분의 재귀호출은 반복문으로 작성하는것이 가능하다. 반복문은 그저 같은 문장을 반복해서 수행하는 것이지만, 메서드를 호출하는 것은 반복문보다 몇 가지 과정, 예를 들면 매개변수 복사와 종류 후 복귀할 주소저장 등,이 추가로 필요하기 때문에 반복문보다 재귀호출의 수행시간이 더 오래 걸린다.
반면에 재귀호출이 주는 논리적 간결함 때문에 특정 상황에서는 단순한구조로 만들어서 알아보기 쉽게 작성하는 것이 논리적 오류가 발생할 확률도 줄어들고 나중에 수정하기 좋다.
'JAVA06강 객체지향 프로그래밍1 > 변수와 메서드' 카테고리의 다른 글
클래스 메서드(static메서드)와 인스턴스 메서드 (0) | 2021.07.19 |
---|---|
메서드의 선언과 구현 (0) | 2021.07.18 |
변수와 메서드 (0) | 2021.07.18 |