[꼼꼼한 개발자] 꼼코더

10. 스프링 입문을 위한 자바 객체 지향의 원리와 이해 - [자바와 절차적/구조적 프로그래밍] - 지역 변수와 메모리, 전역 변수와 메모리 본문

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

10. 스프링 입문을 위한 자바 객체 지향의 원리와 이해 - [자바와 절차적/구조적 프로그래밍] - 지역 변수와 메모리, 전역 변수와 메모리

꼼코더 2022. 12. 27. 02:02
반응형
 

🎁 지역 변수와 메모리 : 스택 프레임에 갇혔어요!

질문을 해볼 테니 답을 해보자

 

질문) “변수는 메모리에 있다”

답 > “예”

 

정답이다. 그렇다면 또 다른 질문을 해보겠다.

 

질문 > “변수는 T 메모리 구역(스태틱, 스택, 힙) 중 어디에 있을까?

답 > “세군데 모두”

 

정답이다. 그런데 세 군데 각각에 있는 변수는 각기 다른 목적을 가진다.

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


 

🏞 지역 변수

지역변수는 스택영역에서 일생을 보낸다.

그것도 스택 프레임 안에서 일생을 보낸다.

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

 

⚡️ 클래스 멤버 변수

클래스 멤버 변수는 스태틱 영역에서 일생을 보낸다.

스태틱 영역에 한 번 자리를 잡으면 JVM이 종료될 때까지 고정된(static) 상태로 그 자리를 지킨다.

 

🙋🏻‍♂️ 객체 멤버 변수

객체 멤버 변수는 힙 영역에서 일생을 보낸다.

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

 


👨🏻‍💻 메서드 스택 프레임 예제

 

9번째 줄이 끝났을 때 T 메모리 스냅샷이다.

10번째 줄에서 square() 메서드를 호출하고 있다.

square() 메서드는 인자값도 있고 반환값도 있다.

 

제어 흐름이 square() 메서드가 선언된 13번째 줄로 이동할 것이다.

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

 

Square() 스택 프레임에는 반환값을 저장할 변수 공간이 맨 아래, 그다음으로 인자를 저장할 변수공간, 그리고 마지막으로 메서드의 지역 변수가 자리 잡는다.

 

15번째 줄이 끝났을 때 T 메모리 스냅샷이다.

16번째 줄을 실행한 후 T 메모리 스냅샷이다.

 

 

주목해야 할 것은 main() 메서드가 가진 변수 k와 square() 메서드가 가진 변수 k가 실제로는 다른 변수라는 것.

이것을 전문 용어로 Call By Value(값에 의한 호출)라고 한다.

 

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

 

18번째 줄을 실행하고 나면 result 변수에 25라는 값이 저장된다.

그럼 호출한 쪽에 반환값을 주고 아래 그림처럼 된다.

 

21번째 줄에서 square() 메서드의 끝을 알리는 닫는 ‘{’를 만나면 square() 메서드 스택 프레임은 사라진다.

그런데 반환값이 있으니 그 값을 돌려주면서 스택에서 사라진다.

 

그럼 10번째 줄은 실행시간에 m변수에 25가 담기고

11번째 줄에 main() 메서드 스택 프레임을 사라지게 하는 ‘{’가 있어, 결국 모든 프로그램이 종료된다.

 

여기서 중요한 부분은 main() 메서드 어디에선가 sqeare() 메서드 내의 지역 변수 result에 접근이 불가하다.

반대 상황도 마찬가지이다.

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

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

 

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

 

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

이런 전달 방식을 값에 의한 전달이라 해서 Call By Value라고 한다.

 

메서드 사이에 값을 전달하거나 반환하는 방법은 메서드의 인자와 반환값으로만 가능하다는 사실을 기억하자.

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

 


 

❌ 전역 변수와 메모리 : 전역 변수 쓰지 말라니까요!

반환값을 넘겨주는 방법 이외에 메서드 사이에 값을 공유하는 방법이 하나 더 있다.

전역 변수를 사용하는 것이다.

 

먼저 int static share라는 코드를 작성한다.

이처럼 static 키워드를 사용하게 되면 아래와 같은 T 메모리 구조를 갖게 되는데

share 변수는 스태틱 영역에 변수 공간이 할당된다. 그것도 Start5 클래스의 멤버로 공간을 만들어 저장된다.

메서드 밖에서 선언된 변수 share는 메서드들 사이에서 공유해서 사용할 수 있는 전역 변수가 된다.

 

앞으로 배운 두 가지 변수 유형을 기억하자

  • 스택 프레임에 종속적인 지역 변수
  • 스택 프레임에 독립적인 전역 변수

 

전역 변수는 사용하게 되면 많은 사람들과 그 값을 공유하여 값이 변화하면 추적해야 하는 어려움이 있다.

결론적으로 전역변수는 피해야 하는 존재이다.

단 상수는 제외 (ex : PI > Math 클래스에 정의되어 있음)

 

다음에 멀티 스레드 프로그램을 학습하여 전역 변수(공유 변수)가 어떤 문제를 일으키는지 알아보자.

 

 

 

 

Comments