JAVA는 JVM(Java Virtual Machine)위에서 작동한다. 따라서 변수, 리터럴, 객체 등 모든 정보들이 JVM의 메모리 영역(Runtime Data Area)에 저장된다. 그 중 객체의 메서드는 어디에 저장될까?
public class Test {
String str = "test";
public void setTest(String str) {
this.str = str
}
}
정말정말 간단한 Test 객체
가 있다. 이 객체는 현재 java파일로 존재할 뿐이지 실제로 사용되진 않은 라이브러리 객체이기때문에 JVM의 메모리 영역에 올라가있진 않다.
Test t1 = new Test();
어디선가 Test 객체를 생성(new)했다. 이 객체는 이제 JVM 메모리 어딘가에 생성되었다는 뜻이다. 그게 어딜까?
바로 메모리 영역 중 힙 영역(Heap Area)이다. 힙 영역은 객체가 생성되는 공간이다.
인스턴스 멤버란 객체에 소속된 필드(field)와 메소드(method)를 말한다.
소속되었다는 것은 객체가 생성(인스턴스화)되어야 사용할 수 있다는 것이다.
위의 Test
객체에서 str
는 인스턴스 필드, setTest()
는 인스턴스 메서드 라고 한다.
객체가 Heap에 생성된다는 것은 알겠는데 객체에 소속된 인스턴스 멤버들은 어디에 저장될까?
객체가 힙에 생성될 때 인스턴스 필드를 포함하여 생성된다. 메모리에 객체와 같이 있다는 것이다.
인스턴스 필드와 다르게 인스턴스 메서드는 힙 영역이 아닌 메서드 영역에 만들어진다. 인스턴스 메서드도 메서드의 일부인데 왜 그런지 의아할 것이다. 이유는 다음과 같다.
인스턴스 메서드는 인스턴스에 따라 변경될 수 있는 필드와는 달리 메서드는 변경되지 않는다. 게다가 메서드는 코드 블록이다. 객체가 생성될 때마다 힙 영역에 메서드가 생성된다면 똑같은 코드 블럭이 중복생성된다는 뜻이고, 이는 메모리 낭비를 불러온다.
대단한 것처럼 작성했지만 생각해보면 그 이유가 별 거 없다.
개발은 결국 추상화의 연속이다. 리팩터링하고 뭔가를 끝없이 수정하는 것은 더 좋은 추상화를 위한 작업이다.
JVM의 메서드 영역도 이와 비슷하다 생각한다. 힙 영역에서 생성된 객체가 공통 개념(메서드)를 가지고 있다면 그것을 추상화하여 추출하는 것이 맞다. 그 결과 메서드는 힙 영역이 아니라 메서드 영역에 저장된다.
Test test1 = new Test(); // Test 객체 생성
Test test2 = new Test(); // Test 객체 생성
동일한 객체를 두 개 만들었다. 지금까지 말한대로라면 객체와 객체에 소속된 필드는 힙 영역에 각각 생성될 것이다.
test1.setTest("test1");
test2.setTest("test2");
test1과 test2는 메서드 영역에 존재하는 동일한 setTest()를 공유하여 사용한다. 하지만 모든 객체가 접근할 순 없고, 해당 객체에서만 사용할 수 있도록 제한이 되어있다.