본문 바로가기

Back-End/JAVA

자바 메모리 구조와 static

  • 메서드 영역 : 클래스 정보를 보관한다.
    • 클래스 정보 : 클래스의 실행 코드(바이트 코드), 필드, 메서드와 생성자 코드 등 모든 실행 코드가 존재한다.
    • static 영역 : static 변수들을 보관한다.
    • 런타임 상수 풀
  • 스택 영역 : 실제 프로그램이 실행되는 영역이다. 자바 실행 시, 하나의 실행 스택이 생성된다. 각 스택 프레임은 지역 변수, 중간 연산 결과, 메서드 호출 등을 포함한다. 스택 영역은 쓰레드별로 하나의 실행 스택이 쌓인다. 즉, 쓰레드 수 만큼 스택 영역이 생성된다.
    • 메서드를 호출할 때마다 하나의 스택 프레임이 쌓이고, 메서드가 종료되면 해당 스택 프레임이 제거된다.
    • 스택 영역에는 메서드 호출 시 사용하는 지역 변수나 메서드 호출 스택 프레임이 저장된다.
  • 힙 영역 : 객체(인스턴스)가 생성되는 영역이다. new 명령어를 사용하면 이 영역을 사용한다.(배열도 new를 사용하기 때문에 힙 영역에 생성된다.) 더이상 참조 되지 않으면 가비지 컬렉터에 의해서 제거된다.
    • 인스턴스 변수는 힙 메모리에 있는 인스턴스와 연결된 상태로 유지된다.

자바에서 특정 클래스로 100개의 인스터스를 생성하면 힙 메모리에 100개의 인스턴스가 생긴다. 각각의 인스턴스는 내부에 변수와 메서드를 가진다. 근데 같은 클래스에서 생성된 인스턴스라도 내부 변수 값은 다르지만, 메서드는 공통된 코드를 공유하기 때문에 인스턴스 변수에는 메모리가 할당 되지만, 메서드에 대한 새로운 메모리 할당은 해주지 않고, 메서드 영역에서 공통으로 관리하고 실행한다!

 

하지만(뚜둥!) 메서드 영역이 관리하는 변수도 있다. 바로 static 변수이다.

만약 100개의 인스턴스가 생성 되어있는데 내가 이 인스턴스 내부에 있는 변수를 공유하고 싶다!! 하면 공유하고 싶은 변수 타입 앞에 static을 붙여주자!! 이러면 static 변수, 정적 변수 또는 클래스 변수라 한다.

또, static이 붙은 멤버 변수는 인스턴스와 무관하게 클래스에 바로 접근해서 사용할 수 있고, 클래스 자체에 소속되어 있다.

그래서 클래스 변수라고 부르는 이유가 있다.

 

클래스 변수 : 클래스 변수는 메서드 영역의 static 영역에 보관되는 변수이다. 메서드 영역은 프로그램 전체에서 사용하는 공용 공간.

클래스 변수는 해당 클래스가 JVM에 로딩 되는 순간 생성된다. 그리고 JVM이 종료될 떄까지 생명주기가 이어진다. 

그래서 static이 정적인 이유가 프로그램 실행 시점에 만들어지고, 프로그램 종료 시점에 제거된다.

 

TIP) static 정적 변수는 인스턴스를 통한 접근은 추천x ,인스턴스 변수에 접근하는 것 처럼 오해할 수 있다. 고로 클래스.static변수로 

직접 클래스로 접근하자!

 

메서드도 클래스 변수와 마찬가지로 메서드 앞에 static을 붙일 수 있다. 이것을 정적 메서드 또는 클래스 메서드라 한다.

그래서 클래스 메서드 또한 클래수 변수 처럼 인스턴스 생성 없이 바로 호출할 수 있다.

참고) static이 붙지않은 인스턴스 메서드는 인스턴스를 생성해야 호출할 수 있다.

특징 static 변수 static 메서드
메모리 할당 시점 클래스가 로드 될 때  클래스가 로드 될 때
공유 여부 모든 객체가 공유 모든 객체에서 동일한 동작 수행
객체 필요 여부 객체 없이 클래스명으로 접근 가능 객체 없이 클래스명으로 호출 가능
사용 목적 공통된 데이터를 저장하거나 관리 공통된 동작이나 유틸리티 기능 제공

 

주의!) static 메서드는 static만 사용할 수 있다! 쉽게 말해서 클래스 내부의 기능을 사용할 때, 정적 메서드는 인스턴스 변수나, 인스턴스 메서드를 사용할 수 없다. 

왜냐?? 정적 메서드는 클래스 이름을 통해 바로 호출할 수 있다. 그래서 인스턴스처럼 참조값 개념이 x. 특정 인스턴스의 기능을 사용하려면 참조값을 알아야 하는데, 정적 메서드는 참조값 없이 호출해서 그렇다.

 

MathUtils 예제

// main 클래스
public class MathArrayUtilsMain {

    public static void main(String[] args) {
        int[] values = {1, 2, 3, 4, 5};
        System.out.println("sum = " + MathArrayUtils.sum(values));
        System.out.println("average = " + MathArrayUtils.average(values));
        System.out.println("MathArrayUtils.min(values) = " + MathArrayUtils.min(values));
        System.out.println("MathArrayUtils.max(values) = " + MathArrayUtils.max(values));
    }
}

//MathUtils 클래스
public class MathArrayUtils {
    private static double result = 0; //sum과 average 값 공유하기 위해 static 변수 사용

    //객체 생성 못하게 막음
    private MathArrayUtils() {}

    public static double sum(int[] values) {
        for (int value : values) {
            result += value;
        }

        return result;
    }

    public static double average(int[] values) {
        return result / values.length;
    }

    public static double min(int[] values) {
        double minimum = values[0];
        for (int i = 0; i < values.length; i++) {
            if (minimum > values[i]) {
                minimum = values[i];
            }
        }
        return minimum;
    }

    public static double max(int[] values) {
        double maximum = values[0];
        for (int i = 0; i < values.length; i++) {
            if (maximum < values[i]) {
                maximum = values[i];
            }
        }
        return maximum;
    }

}

'Back-End > JAVA' 카테고리의 다른 글

불변 객체  (0) 2024.11.18
최상위 부모인 Object 클래스  (0) 2024.11.18
캡슐화(짧음 주의)  (1) 2024.11.16
오버로딩과 this()  (0) 2024.11.16
기본형 변수와 참조형 변수  (0) 2024.11.16