자바 메모리와 변수

자바라는 언어로 개발을 하면서 미처 알지 못했던 변수와 프로그래밍이 어떤 구조로 돌아가는지에 대해 간략히 정리한 내용입니다.

자바 프로그래밍을 하며 알아야할 요소들

스크린샷 2019-06-03 오전 12 31 14

  • JDK
    • 자바 개발 도구
  • JRE
    • 자바 실행 환경
  • JVM
    • 자바 가상 기계

JDK는 자바 소스 컴파일러를 포함하고 있고 JRE는 프로그램 실행기를 가지고 있습니다. 자바의 이러한 구조는 기존에 다른 언어들이 OS등 각기 다른 플랫폼에 따라 배포해야 하는 번거로움을 덜어주기 위해서 입니다. JVM은 개발자가 사용하는 플랫폼에 영향을 받지 않고 구동할 수 있도록 만들어 주는 역할을 합니다.

조금 쉽게 비유하자면 GTA 게임 속 내 캐릭터의 공간을 바탕으로 게임 속 공간의 컴퓨터는 JVM이고 그 컴퓨터 속 운영체제는 JRE, 마지막으로 사용가능한 개발 도구는 JDK의 개념과 유사합니다.

T 메모리

  • 스태틱 영역
    • 클래스의 메모리 공간
  • 스택 영역
    • 메소드의 메모리 공간
  • 힙 영역
    • 객체의 메모리 공간

예제코드

1
2
3
4
5
public class demo1 {
  public static void main(String[] args) {
    System.out.println("Hello World");
  }
}

JRE는 main() 메소드 존재 여부를 확인합니다. 이후 JVM의 실행을 제어하여 전처리과정을 진행합니다. 모든 자바프로그램을 포함하게 되는 java.lang 클래스 패키지를 스태틱 영역에 적재합니다. 이는 우리가 System.out.println()를 사용할 수 있게 만드는 요소이기도 합니다.

이후 작성한 클래스의 경로 및 import등을 스태틱 영역에 가져다 놓고 main() 메소드의 중괄호를 만날때 스택 영역에 main() 메소드를 적재합니다. 이후 매개변수로 선언된 args 변수를 저장할 스택 영역에 메모리 공간을 할당 후 중괄호 안에 있는 System.out.println("Hello World"); 부분을 실행하게 됩니다.

main() 메소드의 종료 시점은 닫는 중괄호를 만났을때 스택 영역에서 할당되었던 공간이 소멸됩니다. 자바는 main() 메소드가 종료가 되면 JRE는 JVM을 종료시키며 할당했던 모든 메모리 공간을 소멸시키면서 프로그램을 종료하게 됩니다.


Call by Value

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
 public static void main(String[] args) {
        int a = 5;
        int b = 10;

        if(a == 5) {
            int k = b + 10;
            b = k;
        } else {
            int j = b + 1;
            b = j;
        }
    }

위에 예제 코드를 통해 프로그램의 실행과정을 살펴보겠습니다.

전처리 과정이 끝난 후 스태틱 영역엔 java.lang 과 클래스 경로가 메모리에 할당되고 스택영역엔 main() 함수가 할당됩니다. 변수 a, b가 선언이 끝난 후 디버깅을 했을때 모습은 다음과 같습니다.

스크린샷 2019-06-03 오전 12 43 45

이후 if문의 조건을 통과 후 첫번째 중괄호에 진입하여 int k = b + 10; 를 만난 후 변수 상태입니다.

스크린샷 2019-06-03 오전 12 46 06

마지막줄인 b = k; 를 만났을때 변수의 모습입니다.

스크린샷 2019-06-03 오전 12 45 23

이를 통해 알 수 있는 사실은 if 블록 스택 프레임에 진입하여 프로그램을 진행할 때 외부에 존재하는 변수 b에 접근하여 값이 변경된 것을 확인할 수 있습니다. 이는 메소드의 스택 영역 메모리상에 적재되어 있기 떄문에 접근이 가능한 것이며 이는 다른 말로 지역 변수라고도 불리며 스택 영역의 메소드가 닫는 중괄호를 만나 종료되면 지역 변수도 함께 소멸됩니다. 이를 통해 우리는 외부에서 내부로 접근하는 것을 불가능하나 반대로 내부에서 외부로는 접근이 가능하다는 점을 알 수 있습니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
 public static void main(String[] args) {
        int a = 5;
        int b;

        b = sum(a);
    }

    public static int sum(int a) {
        int result;
        a = 1;
        result = a;
        return result;
    }

다른 예제를 하나 더 살펴보겠습니다.

b = sum(a); 를 만나기 전까진 스택 영역엔 main() 스택 프레임에 a = 5, b = ?, args 이렇게 세가지가 할당되어 있습니다. 이후 b = sum(a) 를 만나게 되면 아래 public static int sum(int a) 를 진입하게 되며 sum() 이란 스택 프레임이 스택 영역에 할당되고 초기 해당 변수들은result = ?, a = 1, 리턴 = ?값을 가지고 있습니다. 이후 반환값까지 처리가 되면 result = 1, a = 1, 반환값 = 1 인것을 알 수 있습니다. 최종적으로 a는 5 , b는 1이란걸 확인할 수 있습니다.

스크린샷 2019-06-03 오전 1 02 26

자바 메소드에 대한 이해가 있다면 아주 쉬운 개념의 이 구조에 대해 주목해야 할 점은 바로 인자로 넘겨준 변수 a가 이름은 같지만 실질적인 변수 즉 메모리 공간으로 봤을때는 다른 영역이라는 점입니다.

sum() 이란 메소드 안에 a의 변수가 main() 의 a의 변수에 아무런 영향을 미칠 수 없는 것 이것을 우리는 Call By Value라 부르고 값에 의한 호출이라 말합니다.

요약하자면 Call By Value는 메소드를 호출시 매개변수로 전달한 변수는 저장한 값만을 복사하여 전달하는 기능이라 말할 수 있습니다.

Reference