티스토리 뷰

Language/Java

인스턴스 멤버와 정적 멤버

DUCKBAE's 2024. 10. 18. 11:52

인스턴스 멤버와 정적 멤버를 나누는 이유에 대해 알아보려고 한다.


인스턴스 멤버와 정적 멤버

인스턴스 멤버는 객체를 생성한 후 사용할 수 있는 필드와 메서드로 heap 영역에 할당된다.

객체를 생성한 후 사용할 수 있기 때문에 객체 생성 없이 사용할 수 없으며, 객체가 생성되는 시점에 메모리에 할당된다. 즉 모든 객체는 독립적인 속성을 갖게 된다.

인스턴스 멤버를 사용하려면 new 연산자를 사용하여 객체를 생성하고 객체.인스턴스멤버 형태로 사용한다.

 

정적 멤버는 클래스에 고정된 멤버로서 객체를 생성하지 않고 사용할 수 있는 필드와 메서드로 method 영역에 할당된다. 정적 멤버로 선언하려면 필드와 메서드 선언 시 static 키워드를 붙이면 된다.

클래스의 고정된 멤버이기 때문에 클래스 로더가 클래스를 로딩할 때 method 영역에 할당되며 클래스별로 관리된다. 따라서 클래스가 로딩이 끝나면 바로 사용할 수 있다.

정적 멤버를 사용하려면 클래스.정적멤버 형태로 사용한다.

public class Car {

    //정적 필드
    private static int producedCars = 0; //생성된 총 자동차의 개수

    //인스턴스 필드
    private String brand;
    
    //인스턴스 메서드
    public String getBrand() {
    	return brand;
    }
    
    //정적 메서드
    public static double calculatFuelEfficiency(double usedFuel, double distance) {
    	//연비 = 주행거리(km)/ 소모된 연료량(l)
        return distance / usedFuel;
    }
}

//객체 생성
Car car = new Car();

해당 클래스에 대한 내용을 메모리에 할당하면 다음과 같은 구조로 이루어진다.

인스턴스 필드인 brand는 heap 영역에 할당되고, 인스턴스 메서드인 getBrand는 method 영역에 할당된다.

인스턴스 멤버는 heap 영역에 할당된다고 했는데 정확하게는 인스턴스 메서드는 method 영역에 할당된다. 그 이유는 메서드는 코드 블록이기 때문에 객체마다 동일한 동일한 코드 블록을 가지고 있을 필요가 없기 때문이다.

정적 필드인 producedCars와 정적 메서드인 calculateFuelEfficiency는 method 영역에 할당되며, 객체 car 변수는 heap 영역에 할당된 car 객체의 주소를 참조하면서 stack 영역에 할당된다.

 

 

인스턴스 멤버와 정적 멤버는 왜 나눠져야 할까?

인스턴스 멤버와 정적 멤버로 나뉘어져야 하는 이유를 메모리 측면에서 얘기해보려고 한다.

모든 객체가 동일한 값을 갖는 필드에 대해 메모리를 사용하게 된다. 만약 해당 데이터를 정적 필드로 선언하게 되면 하나의 메모리 공간만 차지하게 되므로 메모리 공간 측면에서 더 효율적이다.

 

producedCars 에 대하여 인스턴스 필드로 선언하면, 객체를 생성한 숫자만큼 producedCars 에 대한 메모리 할당이 이루어질 것이다. Car 객체를 100개 생성했다고 가정해보았을 때, heap 영역에는 각각의 객체에 대해 producedCars에 대한 메모리(100 * 4 byte)가 할당되어 총 400 byte 가 소모된다. 반면에, producedCars를 정적 필드로 선언하면 모든 객체가 공유하게 되므로 메모리 공간이 단 하나만 사용된다. 즉 method 영역에 4 byte만 사용하게 되므로 메모리 사용 측면에서 훨씬 효율적이다.

 

따라서 객체의 필드를 선언할 때 모든 객체가 항상 동일한 값을 가지게 된다면 정적 필드로, 객체마다 다른 값을 가져야한다면 인스턴스 필드로 선언하는 것이 좋다.

 

인스턴스 혹은 정적인 멤버들로만 사용했을 때 발생할 수 있는 문제점

인스턴스 멤버만 사용하였을 때

1. 메모리를 낭비하게 된다. (위에서 언급)

2. 같은 데이터를 갖는 필드에 대한 데이터 불일치가 발생하게 된다.

모든 객체가 독립적인 상태를 갖기 때문에 여러 객체에서 같은 데이터에 대해 다르게 설정할 수 있다. 따라서 같은 데이터를 갖는 필드에 대한 데이터의 일관성을 유지하기 어렵게 된다.

 

정적인 멤버만 사용하였을 때

1. 상태 공유의 문제가 발생하게 된다.

정적 멤버는 method 영역에 할당되며 모든 객체가 동일한 값을 참조한다. 객체 별로 다른 상태를 가져야하는 필드에 대하여 어떤 객체가 해당 값을 변경하게 된다면 이를 참조하고 있는 다른 모든 객체에 영향을 미칠 수 있 다.

 

GC 를 곁들인

가비지 컬렉터(GC)는 메모리 관리 기법 중 하나로 동적으로 할당했던 메모리 영역 중에서 필요 없게 된 영역을 해제한다. 주 관리 대상은 heap 영역이다.

정적 멤버는 클래스가 사용되지 않을때까지 method 영역에 유지된다.

인스턴스 멤버는 가비지 컬렉터에 의해 효율적으로 관리된다. heap 영역에 생성된 객체가 더 이상 참조되고 있지 않으면 가비지 컬렉터가 할당된 객체의 메모리를 회수한다.

 


 

다음에는 GC(Garbage Collector) 에 대하여 더 자세하게 알아봐야겠다.

'Language > Java' 카테고리의 다른 글

싱글톤(Singleton)에 대하여  (0) 2024.10.20
상속과 인터페이스의 다형성  (0) 2024.10.20
final 키워드  (0) 2024.10.18
생성자와 오버로딩  (0) 2024.10.18
클래스  (0) 2024.10.17
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함