자바의 변수와 메서드는 메모리에 어떻게 표시될까 1

자바의 변수와 메서드는 메모리에 어떻게 표시될까 1

 

자바 프로그램의 개발과 구동

 

현실 세계에서 소프트웨어, 즉 , 프로그램은 개발자가 개발 도구를 이용해서 개발하고, 운영체제를 통해서 물리적 컴퓨터인 하드웨어에서 구동된다.

자바도 똑같다. 자바 개발 도구인 jdk를 이용해서 개발된 프로그램은 jre에 의해 가상의 컴퓨터인 jvm상에서 구동된다.

컴퓨터 : JVM

운영체제 : JRE

자바개발도구 : JDK

 

 

JDK는 자바 소스 컴파일러인 javac.exe를 포함하고 있다.

JRE는 자바 프로그램 실행기인 java.exe를 포함하고 있다.

 

자바가 이런 구조를 택한 이유는 기존 언어로 작성한 프로그램은 윈도우 95용, 7용, 8용, 리눅스용 등 각 플랫폼용으로 배포되는 설치파일을 따로 준비해야 했던 불편함을 없애기 위해서다.

 

자바 개발자는 본인이 사용중인 플랫폼에 설치된 JVM용으로 프로그램을 작성하고 배포하면 각 플랫폼에 맞는 JVM이 중재자로서 각 플랫폼에서 프로그램을 구동하는데 아무 문제가 없게끔 만들어주는 것이다.

 

 

 

프로그램이 실행될 때 프로그램이 메모리를 사용하는 방식은 코드 실행 영역과 데이터 저장 영역으로 메모리를 분리해서 사용한다.

객체지향 프로그램에서는 데이터 저장영역을 다시 스태틱, 스택, 힙 영역으로 분할해서 사용한다.

 

 

 

자바 키워드 중 절반 이상이 절차적/구조적 프로그래밍 언어에서 유래됐다.

 

 

다시 확인하는 main 메서드

자바에서 main() 메서드가 실행되기 전 JVM에서 수행하는 전처리 작업들

1.java.lang 패키지를 메모리 스태틱 영역에 배치한다.

2.import된 패키지를 메모리 스태틱 영역에 배치한다.

3.프로그램 상의 모든 클래스를 메모리의 스태틱 영역에 배치한다.

 

메모리 상에서 메서드의 공간은 스택이다. Main 메서드가 작동되기 위해 스택 프레임이 스택영역에 할당된다.

더 정확히 말하면 여는 중괄호를 만날 때마다 스택 프레임이 하나씩 생긴다.(class의 중괄호 제외)

 

그리고 main 메서드의 인자 args를 저장할 변수 공간을 스택 프레임의 맨 밑에 확보한다.

즉, 메서드 인자들의 변수 공간을 할당하는 것이다. 

 

 

변수와 메모리

Int i; 이 명령은 메모리 공간에 4바이트 크기의 정수 저장공간을 확보하라는 명령어이다.

JVM은 i 변수를 위해서 공간을 확보하는데, 이 공간은 main() 메서드 스택 프레임 안쪽의 밑 부분 부터 변수 공간을 마련한다.

 

현재 변수 i에 저장된 값은 알수 없는 값이 들어있다. 이전에 해당 공간의 메모리를 사용했던 다른 프로그램이 청소하지 않고간 값을 그대로 가지고 있게 된다.

(그래서 변수 선안만 하고 초기화하지 않으면 컴파일러가 오류를 출력시킨다.)

 

블록 구문과 메모리: 블록 스택 프레임

결과값이 true이기 때문에 If else 블록 중 위의 블록이 실행된다.

그리고 여는 중괄호를 만나면 스택 프레임이 시작된다고 했는데, 여기서 만들어지는 스택 프레임은 메서드의 스택 프레임이 아니라 if문 의 참인 블록의 스택 프레임이다.

(Main() 메서드의 스택 프레임 안에 if문의 블록 스택 프레임이 중첩되어 생성된다.)

 

14번째 줄은 주석처리되어 있는데, 만약 주석을 처리하면 어떻게 될까?

m변수와 p변수가 가지고 있는 값을 더해서 k변수에 대입하는 구문인데, if 문의 블록 스택 프레임이 종료되면 m 변수도 사라지게 된다. 즉 m과 p변수는 if문 안에 있기 때문에 if문이 종료되면 메모리 상에서도 사라지기 때문에 존재하지 않게 된다. 만약 14번 줄에서 주석을 풀면 컴파일러가 컴파일을 할 수가 없다.

 

참고로 if 블록 스택 프레임을 수행하는 중에 if 블록 스택 프레임 외부에 존재하는 k는 접근이 가능하다는 것.

메모리 상에 변수 k가 존재하기 때문에 당연히 접근이 가능하다.

 

“외부 블록에서 내부 블록의 변수에는 접근할 수 없지만 내부 블록에서 외부 블록의 변수에 접근하는 것은 가능하다”

(위부 스택 프레임에서 내부 스택 프레임의 변수에 접근하는 것은 불가능하지만 그 반대는 가능하다.)

 

그래서 스택 메모리 내의 스택 프레임 안의 변수를 지역 변수라고 한다.

그 지역(스택 프레임)에서만 사용할 수 있고, 외부에서는 사용할 수 없기 때문이다. 또한 그 지역이 사라지면 지역 변수도 메모리에서 함께 사라지게된다.

 

 

지역 변수와 메모리 

변수는 스태틱 영역, 스택 영역, 힙 영역 중 어디에 있는 걸까? 정답은 세군데 모두 존재한다.

세 군데 모두 각각 다른 목적을 가진다.

그리고 이름도 지역변수, 클래스 멤버 변수, 객체 멤버변수로 다르다.

 

지역 변수는 스택 영역에서 활동하고 일생을 보낸다. 그것도 스택 프레임 안에서 일생을 보내게 된다.

따라서 스택 프레임이 사라지면 함께 사라진다.

 

클래스 멤버 변수는 스태틱 영역에서 일생을 보낸다. 스태틱 영역에 한번 자리 잡으면 jvm이 종료될 때까지 고정된 - static 상태로 그 자리를 지키고 있다.

 

객체 멤버 변수는 힙에서 일생을 보낸다. 객체 멤버 변수들은 객체와 함께 가비지 컬렉터라고 하는 힙 메모리 회수기에 의해 일생을 마치게 된다.

 

 

메서드 호출과 메모리 - 메서드 호출과정에서 메모리 변화

 

11 번째 줄이 끝나면..

 

메서드 호출이 일어나면 무조건 호출되는 메서드의 스택 프레임이 메모리 스택영역에 새로 생성된다.

11번째 줄에 의해 생성되는 square 메서드 스택 프레임에는 반환값을 저장할 변수 공간이 맨 아래, 그 다음으로 인자를 저장할 변수공간, 마지막으로 메서드의 지역 변수가 자리 잡는다.

 

그 다음 12번째 줄을 실행하면 어떻게 될까?

 

참고로 main 메서드가 가진 변수 k와 square 메서드가 가진 변수 k는 이름만 같지 실제로는 서로 별도의 변수 공간이다. 어려운말로 call by value (값에 의한 호출) 이라고 한다. 

그래서 square 메서드 안의 k 변수에 무슨 짓을 해도 main 메서드 안의 k 변수는 영향이 없다.

 

메서드를 호출할 때마다 해당 메서드의 스택 프레임이 생긴다. 

 

만약 위에서 square () 메서드를 여러번 호출하면 매번 새로운 square() 메서드 스택 프레임이 만들어 졌다가 사라진다.

 

이전에 만들어진 square() 메서드 스택 프레임 내 지역 변수인 result는 다시 만들어진 square() 메서드 스택 프레임의 result 변수와는 완전 별개이다.

 

메서드를 호출하면서 인자로 전달되는 것은 변수 자체가 아니라 변수가 저장한 값만을 복제해서 전달한다.

이러한 전달 방식을 값에 의한 전달이라고 해서 call by value 라고 한다.

 

메서드 사이에 값을 전달하거나 반환하는 방법은 메서드의 인자와 반환값으로만 가능하다는 사실을 알고 있어야 한다.

 

물론 전역 변수(공유변수)도 있긴 하지만 가급적 전역 변수는 사용하지 않는 것이 좋다.

 

 

 

 

참고 : 스프링 입문을 위한 자바 객체 지향의 원리와 이해