[Java] Java 클래스 로딩 과정(Java Class Loading Process)

| 개요(Introduction)


Java에서 객체가 어떻게 형성되고 관리되는 지 이해하려면 .java 파일로 작성되었던 소스코드가 어떻게 JVM위로 로딩되는 지 아는 것이 대단히 중요합니다. 왜냐하면 클래스 로딩 때 발생하는 이슈를 해결할 수 있고 코드 상에서 동적으로 클래스를 로딩하는 구문을 이해할 수 있으며 드물지만 자신만의 클래스 로더(User-defined loader)를 만드는 것이 가능하기 때문입니다.


| 자바 파일(Java file), 클래스 파일(Class file)


자바 파일은 확장자가 .java 인 파일로서 자바 언어로 소스 코드를 작성할 때 그 내용을 적는 파일을 뜻합니다. 그리고 이 자바 파일을 자바 컴파일러로 컴파일한 파일이 바로 .class 확장자를 가진 클래스 파일입니다. 우리가 흔히 이클립스와 같은 IDE 혹은 커맨드 라인에서 javac 명령어를 통해 컴파일했을 때 나오는 파일이죠. 이 클래스 파일을 가지고 자바의 클래스 로더(Class Loader)가 JVM으로 클래스 파일을 로딩합니다.



| 클래스 로딩 과정(Class loading Process)


Java에서 클래스가 로딩 과정은 클래스 로더(Class Loader)가 확장자가 .class 클래스 파일의 위치를 찾아 그것을 JVM위에 올려놓는 과정을 뜻합니다. 여기서 중요한 것은 우리가 만든 .class 확장자를 가진 클래스 파일을 로딩하기 전에 JVM을 실행할 때 이미 JVM을 실행하기 위해서 여러 클래스 파일들을 미리 로딩했다는 것입니다. 각 과정을 하나하나 설명하면 너무 어려우니 아래 그림으로 간략하게 설명하도록 하겠습니다.



<각 클래스 로더의 동작 순서>


JVM을 동작하고 각 클래스들을 로딩하기 위해 JVM을 실행했을 시 각 클래스 로더들은 자신이 호출할 수 있는 클래스들을 호출하여 JVM을 동작하고 클래스들을 JVM에 로딩하기 됩니다.


부트스트랩 클래스 로더(Bootstrap Class Loader)는 위에 $JAVA_HOME/jre/lib/rt.jar 에서 rt.jar에 있는 JVM을 실행시키기 위한 핵심 클래스들을 로딩합니다. Java 어플리케이션 실행시 이 -verbose:class JVM 옵션을 주고 실행시키면 rt.jar에 있는 클래스 파일들이 무수하게 로딩되는 것을 확인 할 수 있습니다.

[Opened C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
[Loaded java.lang.Object from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
[Loaded java.io.Serializable from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
[Loaded java.lang.Comparable from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
[Loaded java.lang.CharSequence from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
[Loaded java.lang.String from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
...

확장 클래스 로더(Extenstion Class Loader)는 $JAVA_HOME/jre/lib/ext 경로에 위치해 있는 자바의 확장 클래스들을 로딩하는 역할을 합니다. 


시스템 클래스 로더(System Class Loader)는 $CLASSPATH에 설정된 경로를 탐색하여 그곳에 있는 클래스들을 로딩하는 역할을 하죠. 저희가 만든 .class 확장자 파일을 이녀석이 로딩합니다.


자 그렇다면 위에 상속받는 것같은 느낌을 풍기는 화살표 표시들은 어떤 것을 의미하는 것일까요? 네 맞습니다. 클래스 로더들은 계층적 구조를 가지도록 생성이 가능하고 각 부모 클래스 클래스 로더에서 자식 클래스 로더를 가지는 형태로 클래스 로더를 만들 수 있습니다. 즉 


Bootstrap <- Extention <- System <- User-defined 


구조를 가지고 있는 거죠.


위의 특징을 포함해서 클래스 로더는 다음과 같은 특징이 있습니다.


- 계층적 구조(Hierarchical)


클래스 로더들은 부모-자식 관계의 계층적 구조를 가지고 있습니다.


- 로딩 요청 위임(Delegate Load Request)


말은 어렵게 들리지만 내용을 알고 보면 쉽습니다. 예를 들어 System Loader가 A라는 클래스를 로딩할 때 그 로딩 요청은 부모 로더들로 거슬러 올라가서 부트스트랩 로더에 다다른 후 그 밑으로 로딩 요청을 수행한다는 것을 의미합니다. 순서를 보면 알기 쉽게 보면 다음과 같습니다.


<Delegate Load Request 동작 과정>


System loader =>(위임) Extension Class Loader =>(위임) Bootstrap Loader 

Bootstrap Loader에서 클래스를 못 찾았을 시 => Extension Class Loader 

Extension Class Loader에서 클래스를 못 찾았을 시 => System Loader

System Loader에서 클래스를 못 찾았을 시 => Exception!


- 가시성 제약 조건(Have Visibility Constraint )


눈치 빠르시 분은 아마 눈치채셨겠지만 클래스 로더 간에는 일종의 범위 룰이 적용되어 있습니다. 부모 로더에서 찾지 못한 클래스는 자식 로더를 이용해서 클래스를 찾지 못하죠. 하지만 반대로 자식로더에서 찾지 못한 클래스는 부모 로더에게 위임해서 클래스를 찾을 수 있습니다.


- 언로드 불가(Cannot unload classes)

 

클래스 로더에 의해 로딩된 클래스들은 다시 JVM상에서 없앨 수 없습니다. 


| 마치며


클래스 로더의 동작과정은 상당히 중요한 부분이라 할 수 있습니다. 개발 중 클래스들이 로딩이 안 될때 java.lang.ClassNotFoundException이 발생하고 삽질한 경험이 많은데요. 이런 클래스 로딩과정들을 정확히 알고 있으면 이런 이슈가 발생할 때마다 빠르고 정확하게 대처할 수 있겠죠.


다음 포스팅에서는 로드타임 동적로딩(Load-time dynamic loading)과 런타임 동적로딩(Runtime dynamic loading)에 대해 알아보겠습니다.


도움이 되셨다면  공감 버튼 꾹 눌러주시면 감사하겠습니다 







이 글을 공유하기

댓글(0)

Designed by JB FACTORY