본문 바로가기
Java

Java 기본 - 자바 메모리 구조 및 static

by KongJiHoon 2024. 12. 25.

** 자바의 메모리 구조는 크게 메서드 영역, 스택 영역, 힙 영역 3개로 나눌 수 있다.

  • 메서드 영역(Method Area) : 메서드 영역은 프로그램을 실행하는데 필요한 공통 데이터를 관리한다. 이 영역은 프로그램의 모든 영역에서 공유한다.
    • 클래스 정보 : 클래스의 실행코드(바이트 코드), 필드, 메서드와 생성자 코드등 모든 실행 코드가 존재한다.
    • static 영역 : static 변수들을 보관
    • 런타임 상수 풀 : 프로그램을 실행하는데 필요한 공통 리터럴 상수를 보관.
  • 스택 영역(Stack Area) : 자바 실행 시, 하나의 실행 스택이 생성된다. 각 스택 프레임은 지역 변수, 중간 연산 결과, 메서드 호출 정보 등을 포함.
    • 스택 프레임 : 스택 영역에 쌍히는 네모 박스가 하나의 스택 프레임이다. 메서드가 실행될 때 마다 하나의 스택 프레임이 쌓이고, 메서드가 종료되면 해당 스택 프레임이 제거된다. 
  • 힙 영역(Heap Area) : 객체(인스턴스)와 배열이 생성되는 영역. 가비지 컬렉션이 이루어지는 주요 영역이며, 더 이상 참조되지 않는 객체는 GC에 의해 제거된다.

 

멤버 변수(필드)의 종류

  • 인스턴스 변수 : static이 붙지 않은 변수
    • static이 붙지 않은 멤버 변수는 인스턴스를 생성해야 사용할 수 있고, 인스턴스에 소속되어 있다. 따라서 인스턴스 변수라 한다.
    • 인스턴스 변수는 인스턴스를 만들 때 마다 새로 만들어진다. 
  • 클래스 변수 : static이 붙은 멤버 변수
    • 클래스 변수, 정적 변수, static변수등으로 부른다. 용어를 모두 사용 
    • static이 붙은 멤버 변수는 인스턴스와 무관하게 클래스에 바로 접근해서 사용할 수 있고, 클래스 자체에 소속되어 있다. 따라서 클래스 변수라 한다.
    • 클래스 변수는 자바 프로그램이 시작할 때 딱 1개가 만들어진다. 인스턴스와 다르게 보통 여러 곳에서 공유하는 목적으로 사용. 메서드 영역에서 관리된다.

변수와 생명주기

  • 지역 변수(매개 변수) : 지역 변수는 스택 영역에 있는 스택 프레임 안에 보관된다. 메서드가 종료되면 스택 프레임도 제거 되는데 이때 해당 스택 프레임에 포함된 지역변수도 함께 제거 된다. 
  • 인스턴스 변수 : 인스턴스에 있는 멤버변수를 인스턴스 변수라 한다. 인스턴스 변수는 힙 영역을 사용. 힙 영역은 GC가 발생하기 전까지는 생존하기 때문에 보통 지역 변수보다 생명주기가 길다.
  • 클래스 변수 : 클래스 변수는 메서드 영역의 static 영역에 보관되는 변수. 메서드 영역은 프로그램 전체에서 사용하는 공용 공간이다. 클래스 변수는 해당 클래스가 JVM에 로딩 되는 순간 생성되어 종료될때까지 생명주기가 이어진다. 

정적 변수 접근 법

** static 변수는 클래스를 통해 바로 접근할 수 있고, 인스턴스를 통해서도 접근이 가능하다.

 

예시코드

Data3

package static1;

public class Data3 {

    private String name;

    public static int count;

    public Data3(String name) {
        this.name = name;
        count++;
    }

    public int getCount() {
        return count;
    }
}

 

DataCountMain3

package static1;

public class DataCountMain3 {

    public static void main(String[] args) {

        Data3 data1 = new Data3("A");
        System.out.println("A counter = " + data1.getCount());

        Data3 data2 = new Data3("B");
        System.out.println("B counter = " + data2.getCount());

        Data3 data3 = new Data3("C");
        System.out.println("C counter = " + data3.getCount());


        // 추가
        // 인스턴스를 통한 접근
        Data3 data4 = new Data3("D");

        System.out.println(data4.getCount());
        System.out.println(Data3.count);
    }
}
  • 실행 결과
A counter = 1
B counter = 2
C counter = 3
4
4

** 위 코드에서 클래스 변수는 객체를 생성할때마다 1씩 증가한다. 클래스 변수는 메서드 영역에서 공통적으로 사용되므로 객체를 새로 생성하더라도 초기화 되지 않는다. 그리고 Data3.count와 같이 클래스를 통해 바로 접근할 수 있다.

 

클래스 메서드

  • static이 붙은 메서드. 정적 메서드 또는 클래스 메서드라 한다.

인스턴스 메서드

  • static이 붙지 않은 메서드는 인스턴스를 생성해야 호출할 수 있다. 이것을 인스턴스 메서드라 한다.

 

static메서드

 

정적 메서드 사용법

  • static메서드는 static만 사용할 수 있다.
    • 클래스 내부의 기능을 사용할 때, 정적 메서드는 static이 붙은 정적 메서드나 정적 변수만 사용할 수 있다.
    • 클래스 내부의 기능을 사용할 때, 정적 메서드는 인스턴스 변수나, 인스턴스 메서드를 사용할 수 없다.
  • 반대로 모든 곳에서 static을 호출할 수 있다.
    • 정적메서드는 공용 기능이다. 따라서 접근 제어자만 허락한다면 클래스를 통해 모든 곳에서 static을 호출할 수 있다.

예시 코드

DecoData

package static2;

public class DecoData {

    private int instanceValue;

    private static int staticValue;

    public static void staticCall() {

//        instanceValue++;
        // 인스턴스 변수 접근, compile error
//        intstanceMethod();
        // 인스턴스 메서드 접근, compile error

        // 정적 변수 접근
        staticValue++;
        staticMethod();

    }

    public void instanceCall() {

        instanceValue++;
        // 인스턴스 변수 접근, compile error
        instanceMethod();
        // 인스턴스 메서드 접근, compile error

        // 정적 변수 접근
        staticValue++;
        staticMethod();


    }

    private void instanceMethod() {

        System.out.println("instanceValue : " + instanceValue);

        staticMethod();
    }

    private static void staticMethod() {
        System.out.println("staticValue : " + staticValue);
    }

}

 

  • staticCall()
    • 정적 메서드이다. static만 사용할 수 있다. 정적 변수, 정적메서드에는 접근할 수 있지만, static이 없는 인스턴스 변수나 인스턴스 메서드에 접근하면 컴파일 오류가 발생한다.
  • instanceCall()
    • 인스턴스 메서드로, 모든 곳에서 공용인 static을 호출할 수 있다. 따라서 정적변수, 정적메서드에 접근할 수 있다. 물론 인스턴스 변수, 인스턴스 메서드에도 접근가능.

DacoDataMain

package static2;

import static static2.DecoData.staticCall;

public class DecoDataMain {

    public static void main(String[] args) {
        System.out.println("1. 정적 호출");

        staticCall();

        System.out.println("2. 인스턴스 호출1" );
        DecoData data1 = new DecoData();
        data1.instanceCall();

        System.out.println("3. 인스턴스 호출2" );
        data1.instanceCall();

        // 추가
        // 인스턴스를 통한 접근
        DecoData data3 = new DecoData();
        staticCall();

        // 클래스를 통한 접근
        staticCall();

    }
}

 

정적메서드가 인스턴스의 기능을 사용할 수 없는 이유

  • 정적 메서드는 클래스의 이름을 통해 바로 호출할 수 있다. 그래서 인스턴스처럼 참조값의 개념이 없다. 특정 인스턴스의 기능을 사용하려면 참조값을 알아야 하는데, 정적 메서드는 참조값없이 호출한다. 따라서 정적메서드 내부에서 인스턴스 변수나 인스턴스 메서드를 사용할 수 없다.

 

출처: https://www.inflearn.com/course/%EA%B9%80%EC%98%81%ED%95%9C%EC%9D%98-%EC%8B%A4%EC%A0%84-%EC%9E%90%EB%B0%94-%EA%B8%B0%EB%B3%B8%ED%8E%B8/dashboard

'Java' 카테고리의 다른 글

Java 기본 - 상속  (0) 2025.01.03
Java 기본 - final  (0) 2025.01.02
Java 기본 - 접근제어자  (0) 2024.12.21
Java 기본 - 생성자  (0) 2024.12.08
Java 기본 - 객체지향 프로그래밍  (1) 2024.12.07