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

전역 변수(static)와 메모리: 왜 주의해서 써야 하는가?

1space 2025. 6. 29. 16:12

스프링입문을 위한 자바 객체지향의 원리와 이해』로 공부한 내용을 정리한 글입니다.

 

자바에서 프로그램이 실행되면 메모리는 여러 영역으로 나누어 사용됩니다. 특히 메서드 실행과 관련된 지역 변수는 스택(stack) 영역에, 반면에 static 변수 같은 전역 변수는 클래스 영역(메서드 영역)에 저장됩니다.

예제

public class Start5 {
    static int share;

    public static void main(String[] args) {
        share = 55;
        int k = fun(5, 7);
        System.out.println(share);
    }

    private static int fun(int m, int p) {
        share = m + p;
        return m - p;
    }
}

 

 

실행 흐름과 메모리 스냅샷

프로그램 시작 전

  • Start5 클래스가 메모리에 올라가면서 static int share 변수가 클래스 영역(T 메모리)에 0으로 초기화됨.

4번째 줄 실행: share = 55;

  • 전역 변수 share에 55 저장됨.

5번째 줄 실행: fun(5, 7);

  • fun() 메서드가 호출되면 스택에 fun 스택 프레임이 만들어지고 m=5, p=7이 저장됨.
  • 동시에 이전 main() 스택 프레임도 유지됨.

13번째 줄 실행: share = m + p;

  • share = 5 + 7로 계산되어 share = 12로 덮어씀.
  • 이때 main()에 있던 share = 55는 사라짐이 아니라, 단지 전역 공간의 값이 바뀐 것.

16번째 줄 리턴: return m - p;

  • fun() 스택 프레임이 제거되면서 main으로 되돌아감.
  • 리턴값 -2는 변수 k에 저장됨.
  • 이 시점의 메모리엔 share = 12, k = -2

 

여기서 중요한 점!

  • share는 모든 메서드가 공유하는 전역 변수입니다.
  • 함수 간 값을 주고받기 위해서 지역변수를 인자로 넘기는 것이 일반적이지만, 여기서는 함수 밖에 있는 전역 변수 share를 두 함수가 같이 접근합니다.
  • 문제는 규모가 커지면 이 값이 언제, 어디서 바뀌었는지 추적이 매우 어려워진다는 점입니다.

 

전역 변수는 왜 피하라고 할까?

  • 전역 변수는 코드 어디서든 접근 가능하므로 추적이 어려움.
  • 여러 메서드에서 동시에 값을 바꿀 수 있어 버그 발생 위험 증가.
  • 특히 멀티 스레드 환경에선 경합 조건(race condition)까지 발생할 수 있음.

 

전역 변수는 반드시 피해야 하나요?

반드시 그런 건 아닙니다. 읽기 전용으로 공유할 상수(Constant) 같은 경우에는 static 변수로 선언해서 사용하는 것이 좋습니다.

예:

System.out.println(Math.PI);  // Math 클래스의 전역 상수 PI

이처럼 불변의 공유 데이터는 전역 변수로 선언해도 괜찮습니다.

 

정리

변수 종류 저장 위치 특징
지역 변수 스택 프레임 메서드 실행 시 생성되고 종료 시 제거됨
전역 변수 (static) 클래스 영역(T 메모리) 프로그램 전체에서 공유됨, 변경 시 주의 필요