일반적으로 우리가 만드는 class는 static 영역에 생성된다. static 키워드로 만든 정적 변수와 정적 메소드의 경우는 프로그램이 종료되기 전까지 사용이 가능하다. 또한 static이라는 키워드를 통해 static 영역에 할당된 메모리는 모든 객체가 공유하는 메모리라는 장점을 지니지만 GC(Garbage Collector)의 관리 영역 밖에 존재해 static을 자주 사용하면 프로그램 종료시까지 메모리가 할당된 채로 존재해 시스템 퍼포먼스에 악영향을 주게 된다.
Static이 저장되는 위치
Permanent vs. Metaspace
- Permanent
- JDK 8 이전까지 존재했던 메소드 영역
- 클래스 내부의 메타 데이터들을 저장하는 영역
- Heap영역에 속하며 클래스, 메소드 메타 데이터, 정적 객체, 정적 변수, constant pool 등을 관리
- JVM에 의해 크기가 강제되던 영역
- JDK 7버전에서의 PermSize는 약 82MB
- Metaspace
- JDK 8 이후에 생긴 영역으로 permanent영역이 관리하던 일부 정보를 저장
- Static Object는 Heap 영역으로 옮겨져서 GC의 대상이 최대한 될 수 있도록 처리됨
- Native 메모리 영역으로 취급되어 OS에서 관리되기 때문에 개발자는 영역 확보의 상한을 크게 의식할 필요가 없어짐
- 각종 메타 정보를 OS가 관리하는 영역으로 옮겨 Permanent 영역의 사이즈 제한을 없앤 것이라고 볼 수 있음
- JDK 8버전에서의 MetaspaceSize는 약 17조MB
Static 변수
static 변수는 클래스 변수로 static이라는 키워드가 붙어 있고 클래스 중괄호 안, 메소드 밖에 선언되어 있는 변수이다. 메모리에 한번 할당되어 프로그램이 종료될 때 해제되기 때문에 객체를 생성하지 않아도 접근이 가능하고 여러 객체에서 같은 메모리를 공유한다.
일반적으로 static 변수는 상수의 값을 갖는 경우가 많아 public이나 final 키워드와 함께 사용되는 편이다.
Static 메소드
static 메소드는 객체의 생성 없이 호출이 가능하며, 객체에서는 호출이 불가능하다. 또 static 메소드에서는 static이 아닌 인스턴스 변수에는 접근이 불가능하다. 클래스 변수이거나 매개변수, 메소드 내에 선언된 변수에만 접근이 가능하다.
Static을 지양해야 하는 이유
메모리 문제
static은 프로그램 실행 시점에서 메모리에 할당을 하며, 웬만하면 프로그램 종료 시점까지 메모리에서 해제되지 않아 너무 많이 할당되면 성능이 저하된다.
동시성 이슈 문제
static은 전역에서 접근이 가능하므로 별도의 동기화 전략을 수립해야 한다.
런타임 다형성 불가
static으로만 이루어진 메소드를 사용하는 객체의 경우, 해당 객체를 메모리로 할당하여 사용하는 것이 아니고 객체.메소드로 바로 접근하여 호출한다.
객체의 상태 이용 불가
정적 메소드 안에서는 클래스의 인스턴스 변수를 사용할 수 없기 때문에 필요로 하는 인자는 모두 외부에서 넣어줘야 한다. 일반 메소드라면 객체 내의 상태를 통해 해당 메소드를 구현해줄 수 있어 변화하는 상태에 따라 다채로운 구현이 가능한데 정적 메소드가 많아지면, 외부 값에 의존하는 수동적인 객체가 된다.
테스트 어려움
정적 필드는 전역으로 관리되기 때문에 프로그램 전체에서 이 필드에 접근하고 수정할 수 있다. 따라서 해당 필드를 추론하기 어려워 테스트하기 까다롭다.
Static을 사용하는 경우
상수 정의
절대로 변하지 않는 변수인 상수는 객체 내에서 매번 일반 변수로 정의하기 보다는 한번 정적 변수로 정의해 놓으면 메모리를 아낄 수 있다.
유틸리티 클래스 정의
유틸리티 클래스는 인스턴스 메소드와 인스턴스 변수를 제공하지 않고, 데이터 처리를 위한 정적 메소드만 존재하는 클래스로 java에서 Math 클래스 같은 경우를 유틸리티 클래스라 한다. 이렇게 애초부터 객체의 상태를 신경쓰지 않아도 되고, 여러 객체들이 공통적으로 사용하는 로직의 경우 static으로 선언하는 것이 좋다.
참고 자료 :
https://steady-coding.tistory.com/603
https://mi-nya.tistory.com/251
https://johngrib.github.io/wiki/java8-why-permgen-removed/#fnref:compare
'공부 > Java' 카테고리의 다른 글
[공부/Java] 고정 소수점과 부동 소수점, 왜 컴퓨터는 소수 계산을 정확하게 못할까? (0) | 2022.12.28 |
---|---|
[공부/Java] Runtime Data Area (0) | 2022.12.28 |
[공부/Java] JVM, JRE, JDK (0) | 2022.12.24 |
[공부/Java] JVM 구성 - Class Loader, Execution Engine, Garbage Collector (0) | 2022.12.24 |
[공부/Java] 자바의 main() 메소드, 예외, 예외 처리, try-catch-finally, 예외 클래스 (0) | 2022.07.11 |