스태틱 영역에 존재하는 인스턴스 메서드
자바에서 new 연산자로 생성된 모든 객체는 JVM 내 단 하나의 힙(Heap)이라는 메모리 영역에 저장되어 모든 스레드가 이를 공유한다. 객체는 속성과 기능, 두 종류의 구성요소로 이루어져 있으며, 이러한 속성과 기능을 그 객체의 멤버라고 한다. 이때 객체 생성자를 통해 객체를 생성하면 클래스에 정의된 속성(인스턴스 변수)과 기능(인스턴스 메서드)이 모두 해당 객체와 함께 힙에 생성되었을 것이라고 생각했었다. 하지만 놀랍게도 인스턴스 변수는 힙 영역(해당 객체 내)에 존재하지만 인스턴스 메서드는 힙 영역에 존재하지 않고 스태틱 영역에 단 하나만 존재한다. 어떻게 이런 일이 일어날 수 있는 것인가?
변수와 달리 메서드는 변하지 않는다.
우선 변수의 특징은 애플리케이션의 동작 과정에서 특정 이벤트에 따라 언제든지 변할 수 있다. 또한 객체별로 다른 값을 가질 수 있기도 하다. 하지만 메서드는 변하지 않는다. 만약에 메모리(힙 영역) 상에 모든 객체별로 각각 메서드를 가지고 있을지라도 이들은 다른 메서드가 아닌 것인데 동일한 메서드를 수많은 객체들이 들고있다면 이는 메모리를 비효율적으로 관리하는 꼴이다. 아울러 객체가 무수히 많다면? 또는 메서드 로직이 굉장히 무겁다면? 이는 더욱 큰 (비효율적인) 메모리 소모를 유발할 것이다.
인스턴스 메서드를 스태틱 영역에 할당하는 지능적인 JVM
이러한 메모리 문제를 해결하기 위해 JVM은 애초에 인스턴스 메서드를 객체별 힙 영역에 할당하는 게 아니라 스태틱 영역에 단 하나만 보유하도록 할당한다.
예를 들어, 다음과 같이 main 메서드에서 Test 객체를 생성하여 Test 객체 내 hello라는 인스턴스 메서드를 호출한다고 해보자.
class Practice {
public static void main(String[] args) {
Test test = new Test();
test.hello();
}
}
class Test {
void hello() {
System.out.println("hello!!");
}
}
이때 코드만 놓고 보면 hello라는 인스턴스 메서드는 힙 영역에 있는 Test 객체 안에 있을 것만 같다. 하지만 앞서 언급했듯이 hello 메서드는 스태틱 영역에 단 하나만 존재한다. 즉, 실제 동작은 JVM에 의해 아래와 같이 동작한다고 볼 수 있다.
class Practice {
public static void main(String[] args) {
Test test = new Test();
Test.hello(test);
}
}
class Test {
static void hello(Test test) {
System.out.println("hello!!");
}
}
앞선 코드와 달라진 점은 당초 인스턴스 메서드였던 hello 메서드가 정적 메서드로 선언이 되었고 매개변수로 Test 타입의 참조변수를 입력받는 것이다. 이에 Test 객체를 생성하고 hello 메서드를 호출하는 main 메서드에서는 정적 메서드를 호출하는 방식("클래스명.메서드명" 방식으로)으로 hello 메서드를 호출하고 있으며 인자로 앞서 생성했던 객체의 참조변수를 전달하고 있다. 즉, 메서드는 스태틱 영역에 접근하듯이 접근하고, 변수는 힙 영역에 접근하듯이 접근하는 것이라고 볼 수 있다.
참고자료
- 도우출판 "자바의 정석"
- 위키북스 "스프링 입문을 위한 자바 객체 지향의 원리와 이해"
'Technology > Java' 카테고리의 다른 글
Java의 변수에 대해 얇고 넓게 샅샅이 뜯어보자 (0) | 2022.08.01 |
---|---|
JVM이란 무엇인가? JVM 파헤쳐보기 (2) | 2022.07.23 |
Scanner close 반드시 해야할까? (6) | 2022.02.15 |
캡슐화(정보 은닉)를 위한 Java의 접근 제어자 이해하기 (2) | 2022.02.05 |
Java 프로그램의 실행원리(feat. JVM) (0) | 2021.10.17 |