๐ JAVA 02 - JVM ClassLoader์ ์คํ ๊ตฌ์กฐ
JVM ClassLoader์ Proxy ๊ตฌ์กฐ
ํ์ต ๋ชฉํ
์ด๋ฒ ์ฃผ์ ์ ํต์ฌ์:
- JVM์ ์ Runtime Dynamic Loading ๊ตฌ์กฐ๋ฅผ ์ฌ์ฉํ๋๊ฐ?
- ๋ถ๋ชจ ์์ ๋ชจ๋ธ์ ์ ํ์ํ๊ฐ?
- ํต์ฌ ํด๋์ค๋ฅผ ์ ๋ณดํธํด์ผ ํ๋๊ฐ?
- Proxy๋ ์ ์ฌ์ฉํ๋๊ฐ?
- Spring์ ์ ํ๋ก์ ๊ธฐ๋ฐ ํ๋ ์์ํฌ์ธ๊ฐ?
- Reflection๊ณผ Proxy๋ ์ด๋ค ๊ด๊ณ์ธ๊ฐ?
- ์ด์ ํ๊ฒฝ์์ ์ด๋ค ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋๊ฐ?
๋ฅผ ์ฐ๊ฒฐํด์ ์ดํดํ๋ ๊ฒ์ด๋ค.
์ฆ:
Java Runtime System ์ ์ฒด ํ๋ฆ
์ ์ดํดํ๋ ๊ฒ์ด ๋ชฉํ๋ค.
JVM ์คํ ๊ตฌ์กฐ
1
2
3
4
5
6
7
8
flowchart TD
A[.java Source] --> B[javac Compile]
B --> C[.class Bytecode]
C --> D[JVM Start]
D --> E[ClassLoader]
E --> F[Runtime Data Area]
F --> G[Execution Engine]
Java๋:
Runtime ์์ ์ ํด๋์ค๋ฅผ ๋ก๋ฉํ๋ค.
์ด๊ฒ C/C++์ ๊ฐ์ฅ ํฐ ์ฐจ์ด ์ค ํ๋๋ค.
ClassLoader๋ ๋ฌด์์ธ๊ฐ?
ClassLoader๋:
.class Bytecode๋ฅผ JVM ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฌํ๋ ๊ฐ์ฒด
๋ค.
Java์ ๋ชจ๋ ํด๋์ค๋ ๋ฐ๋์ ClassLoader๋ฅผ ํตํด ๋ก๋ฉ๋๋ค.
JVM ClassLoader ๊ตฌ์กฐ
1
2
3
4
5
flowchart TD
A[Bootstrap ClassLoader]
--> B[Platform ClassLoader]
--> C[Application ClassLoader]
1. Bootstrap ClassLoader
๊ฐ์ฅ ์ต์์ ๋ก๋.
ํต์ฌ Java ํด๋์ค๋ฅผ ๋ก๋ฉํ๋ค.
๋ํ:
- java.lang
- java.util
- java.io
์:
1
System.out.println(String.class.getClassLoader());
๊ฒฐ๊ณผ:
1
null
Bootstrap Loader๋ Native(C++) ๊ธฐ๋ฐ์ด๋ผ null๋ก ํํ๋๋ค.
2. Platform ClassLoader
Java 9 ์ด์ ์๋ Extension Loader์๋ค.
์ญํ :
JDK ํ๋ซํผ ๊ธฐ๋ฅ ๊ด๋ จ ํด๋์ค ๋ก๋ฉ
๋ํ:
- java.sql
- java.xml
- crypto
- logging
์ฆ:
Bootstrap์ JVM ์์กด ํต์ฌ,
Platform์ ํ๋ซํผ ๊ธฐ๋ฅ ํ์ฅ์ด๋ค.
3. Application ClassLoader
๊ฐ๋ฐ์๊ฐ ์์ฑํ ํด๋์ค ๋ก๋ฉ.
1
2
3
4
5
6
7
8
public class Main {
public static void main(String[] args) {
System.out.println(
Main.class.getClassLoader()
);
}
}
๋ถ๋ชจ ์์ ๋ชจ๋ธ (Parent Delegation Model)
ClassLoader์ ํต์ฌ ์ค๊ณ๋ค.
1
2
3
4
5
6
7
8
9
flowchart TD
A[ํด๋์ค ๋ก๋ฉ ์์ฒญ]
--> B[๋ถ๋ชจ Loader ์์]
B --> C{๋ถ๋ชจ๊ฐ ํด๋์ค ๋ฐ๊ฒฌ?}
C -->|YES| D[๋ถ๋ชจ Loader ์ฌ์ฉ]
C -->|NO| E[ํ์ฌ Loader ๋ก๋ฉ]
์ ์ด๋ ๊ฒ ์ค๊ณํ๋๊ฐ?
ํต์ฌ ๋ชฉ์ ์:
- ๋ณด์
- JVM ์์ ์ฑ
- ํ์ ์์ ์ฑ
- ํด๋์ค ์ค๋ณต ๋ฐฉ์ง
์ด๋ค.
ํต์ฌ ํด๋์ค๋ฅผ ์ ๋ณดํธํด์ผ ํ๋๊ฐ?
๋ง์ฝ ๋ถ๋ชจ ์์์ด ์๋ค๋ฉด:
1
2
3
4
package java.lang;
public class String {
}
๊ฐ์ fake ํด๋์ค๋ฅผ ๋ง๋ค ์ ์๋ค.
๊ทธ๋ฌ๋ฉด JVM์:
- ์ง์ง String
- ๊ฐ์ง String
์ค ์ด๋ค ๊ฑธ ์จ์ผ ํ ์ง ๋ชจ๋ฅธ๋ค.
์ ์ํํ๊ฐ?
1. JVM ์ ๋ขฐ์ฑ ๋ถ๊ดด
Java๋:
- Object
- String
- Thread
- Class
๊ฐ์ ํต์ฌ ํด๋์ค ๊ธฐ๋ฐ์ผ๋ก ๋์ํ๋ค.
์ด๊ฒ ์์กฐ๋๋ฉด JVM ์ ์ฒด ์์ ์ฑ์ด ๋ฌด๋์ง ์ ์๋ค.
2. ๋ณด์ ๋ฌธ์
์:
1
java.security.SecurityManager
๊ฐ์ ๊ฑธ ์์กฐํ๋ฉด ๊ถํ ์์คํ ์์ฒด๊ฐ ๊นจ์ง ์ ์๋ค.
3. ํ์ ์์ ์ฑ ๋ถ๊ดด
Java๋:
โํต์ฌ ํด๋์ค๋ ์์ ํ๋คโ
๋ฅผ ์ ์ ๋ก ๋์ํ๋ค.
ํต์ฌ ํด๋์ค๊ฐ ๋ณ์กฐ๋๋ฉด:
- equals
- hashCode
- casting
- synchronization
์ ๋ถ ์ํํด์ง๋ค.
ํด๋์ค ์๋ณ ๊ธฐ์ค
Java์์ ํด๋์ค๋:
1
ํด๋์ค ์ด๋ฆ + ClassLoader
์กฐํฉ์ผ๋ก ์๋ณ๋๋ค.
์ฆ:
๊ฐ์ ํด๋์ค๋ผ๋ Loader๊ฐ ๋ค๋ฅด๋ฉด ๋ค๋ฅธ ํ์ ์ด๋ค.
Loading โ Linking โ Initialization
ํด๋์ค ๋ก๋ฉ์ ๋จ์ ํ์ผ ์ฝ๊ธฐ๊ฐ ์๋๋ค.
1
2
3
4
5
flowchart LR
A[Loading]
--> B[Linking]
--> C[Initialization]
Loading
.class ์ฝ๊ธฐ.
Linking
๊ฒ์ฆ ๋ฐ ๋ฉ๋ชจ๋ฆฌ ์ฐ๊ฒฐ.
์ธ๋ถ:
- Verify
- Prepare
- Resolve
Bytecode ๊ฒ์ฆ์ด ์ฌ๊ธฐ์ ์ํ๋๋ค.
Initialization
์ ์ ๋ณ์ ์ด๊ธฐํ ์ํ.
1
2
3
static {
System.out.println("init");
}
Runtime Dynamic Loading
Java ํต์ฌ ํน์ง ์ค ํ๋๋ค.
1
2
3
4
Class<?> clazz =
Class.forName(
"com.mysql.jdbc.Driver"
);
์คํ ์์ (Runtime)์ ํด๋์ค ๋ก๋ฉ ๊ฐ๋ฅ.
์ ์ค์ํ๊ฐ?
์ด ๊ตฌ์กฐ ๋๋ถ์ Java๋:
- Spring
- JDBC
- Tomcat
- JPA Proxy
- AOP Proxy
๊ฐ์ ๊ฐ๋ ฅํ ๋ฐํ์ ํ์ฅ ๊ตฌ์กฐ๋ฅผ ๊ฐ์ง๋ค.
Reflection
Reflection์:
Runtime ์์ ์ ํด๋์ค ์ ๋ณด๋ฅผ ๋ถ์/์กฐ์
ํ๋ ๊ธฐ์ ์ด๋ค.
1
2
3
4
Class<?> clazz = User.class;
Method[] methods =
clazz.getDeclaredMethods();
Spring์ ์ Reflection์ ์ฌ์ฉํ๋๊ฐ?
๋ํ์ ์ผ๋ก:
- Bean ์์ฑ
- DI
- AOP
- Annotation ๋ถ์
๋๋ฌธ์ด๋ค.
์ฆ:
Spring ๋ด๋ถ๋ Reflection ๊ธฐ๋ฐ Runtime Framework
๋ผ๊ณ ๋ณผ ์ ์๋ค.
Proxy๋ ๋ฌด์์ธ๊ฐ?
Proxy ํต์ฌ์:
โ์ค์ ๊ฐ์ฒด ๋์ ํธ์ถ์ ๊ฐ๋ก์ฑ๋ ๊ฐ์ฒดโ
๋ค.
์ผ๋ฐ ํธ์ถ ๊ตฌ์กฐ
1
2
3
4
flowchart TD
A[Client]
--> B[Real Object]
Proxy ๊ตฌ์กฐ
1
2
3
4
5
flowchart TD
A[Client]
--> B[Proxy]
--> C[Real Object]
์ฆ:
์ค๊ฐ์ ๋๋ฆฌ ๊ฐ์ฒด๋ฅผ ๋๋ค.
์ ๊ตณ์ด Proxy๋ฅผ ์ฐ๋๊ฐ?
ํต์ฌ ์ด์ :
๋น์ฆ๋์ค ๋ก์ง ์์ ์์ด ๊ณตํต ๊ธฐ๋ฅ ์ถ๊ฐ
๋ค.
๋ํ ๊ณตํต ๊ธฐ๋ฅ:
- ๋ก๊ทธ
- ํธ๋์ญ์
- ๊ถํ ๊ฒ์ฌ
- ์บ์
- ์ฑ๋ฅ ์ธก์
@Transactional ์ค์ ๊ตฌ์กฐ
1
2
3
@Transactional
public void order() {
}
์ค์ ๋ด๋ถ ๊ตฌ์กฐ:
1
2
3
4
5
6
7
8
9
sequenceDiagram
Client->>Transaction Proxy: order()
Transaction Proxy->>Transaction Manager: begin()
Transaction Proxy->>Real Service: order()
Transaction Proxy->>Transaction Manager: commit()
์ฆ:
ํธ๋์ญ์ ๋ก์ง์ Proxy๊ฐ ๋์ ์ํ
ํ๋ค.
Spring์ด Proxy๋ฅผ ์ฌ์ฉํ๋ ์ด์
Spring์:
- AOP
- Transaction
- Security
- Cache
- Async
๊ฑฐ์ ๋๋ถ๋ถ Proxy ๊ธฐ๋ฐ์ด๋ค.
์ฆ:
Spring์ Proxy Framework์ ๊ฐ๊น๋ค.
Proxy ์ข ๋ฅ
1. ์ ์ Proxy
์ง์ ํด๋์ค ์์ฑ.
1
2
class PaymentProxy {
}
๋ฌธ์ :
๋๋ฌด ๊ท์ฐฎ๋ค.
2. ๋์ Proxy
๋ฐํ์์ ์๋ ์์ฑ.
๋ํ:
- JDK Dynamic Proxy
- CGLIB
JDK Dynamic Proxy
์ธํฐํ์ด์ค ๊ธฐ๋ฐ.
1
2
public interface UserService {
}
ํ์.
CGLIB
์์ ๊ธฐ๋ฐ Proxy.
1
Proxy extends UserService
Spring Boot๋ ๋๋ถ๋ถ CGLIB ์ฌ์ฉ.
์ค๋ฌด ํต์ฌ ๋ฌธ์
self invocation ๋ฌธ์
1
2
3
4
5
6
7
8
@Transactional
public void a() {
b();
}
@Transactional
public void b() {
}
๋ด๋ถ ํธ์ถ:
1
b();
์ Proxy๋ฅผ ์ ํ๋ค.
์ฆ:
Transaction ์ ์ฉ ์๋ ์ ์๋ค.
์ด๊ฑด ๋ฉด์ ๋จ๊ณจ์ด๋ค.
์ด์ ํ๊ฒฝ ํต์ฌ ๋ฌธ์
ClassLoader Memory Leak
ํนํ:
- Tomcat
- DevTools
- Hot Reload
ํ๊ฒฝ์์ ์ ๋ช ํ๋ค.
์ ๋ฐ์ํ๋๊ฐ?
ClassLoader๊ฐ GC๋์ง ๋ชปํ๋ฉด:
ํด๋น Loader๊ฐ ๋ก๋ฉํ ํด๋์ค ์ ์ฒด๊ฐ GC ๋ถ๊ฐ
์ํ๊ฐ ๋๋ค.
๋ํ ์์ธ:
- static ๊ฐ์ฒด
- ThreadLocal
- cache ๊ฐ์ฒด
์ค์ ์ฅ์ ์ฌ๋ก
์ฌ๋ฐฐํฌ ๋ฐ๋ณต ํ:
1
java.lang.OutOfMemoryError: Metaspace
๋ฐ์.
์์ธ:
- ์ด์ WebApp ClassLoader ์ฐธ์กฐ ์ ์ง
- static cache ๋์
์ฑ๋ฅ ๊ด์
ClassLoader ์์ฒด๋ ๋ณ๋ชฉ์ด ์๋๋ค.
์ค์ ๋ฌธ์ ๋:
- reflection ๋จ์ฉ
- excessive proxy
- startup latency ์ฆ๊ฐ
๋ค.
์ค์ ์ด์ ๋ณ๋ชฉ์ ๋๋ถ๋ถ:
- DB
- Network
- External API
๋ค.
Trade-off
์ฅ์
- ์ ์ฐ์ฑ
- ๋ฐํ์ ํ์ฅ
- ๋์ ๊ตฌ์กฐ
- ๊ณตํต ๊ด์ฌ์ฌ ๋ถ๋ฆฌ
๋จ์
- startup ๋น์ฉ ์ฆ๊ฐ
- ๋ฐํ์ ์ค๋ฅ ์ฆ๊ฐ
- ๋๋ฒ๊น ์ด๋ ค์
- classloader leak ์ํ
์์ฃผ ๋ฐ์ํ๋ ์ค์
1. Reflection ๋จ์ฉ
๋ถํ์ํ reflection ๋ฐ๋ณต.
2. self invocation
Proxy ์ฐํ ๋ฌธ์ .
3. static ๊ฐ์ฒด ๋์
์ฌ๋ฐฐํฌ ํ๊ฒฝ ์น๋ช ์ .
4. final ๋ฉ์๋ ์ฌ์ฉ
CGLIB Proxy ๋ถ๊ฐ ๊ฐ๋ฅ์ฑ.
๋ฉด์ ๊ผฌ๋ฆฌ ์ง๋ฌธ
Q1. ๋ถ๋ชจ ์์ ๋ชจ๋ธ์ ์ ํ์ํ๊ฐ?
ํต์ฌ:
- ๋ณด์
- JVM ์์ ์ฑ
- Java Core ๋ณดํธ
Q2. ํต์ฌ ํด๋์ค๋ฅผ ์ ๋ณดํธํด์ผ ํ๋๊ฐ?
ํต์ฌ:
- ํ์ ์์ ์ฑ
- JVM ์ ๋ขฐ์ฑ
- ๋ณด์ ์ ์ง
Q3. Spring์ ์ Proxy๋ฅผ ์ฌ์ฉํ๋๊ฐ?
ํต์ฌ:
- ๊ณตํต ๊ด์ฌ์ฌ ๋ถ๋ฆฌ
- Transaction/AOP ๊ตฌํ
Q4. self invocation ๋ฌธ์ ๋?
ํต์ฌ:
- ๋ด๋ถ ํธ์ถ์ Proxy๋ฅผ ๊ฑฐ์น์ง ์์
์ข์ ๋ต๋ณ ์์
JVM์ Runtime ์์ ์ ClassLoader๋ฅผ ํตํด ํด๋์ค๋ฅผ ๋ก๋ฉํฉ๋๋ค.
๋ถ๋ชจ ์์ ๋ชจ๋ธ์ ํตํด Java ํต์ฌ ํด๋์ค๋ฅผ ๋ณดํธํ๋ฉฐ JVM ์์ ์ฑ๊ณผ ํ์ ์์ ์ฑ์ ์ ์งํฉ๋๋ค.
๋ํ Spring์ Proxy์ Reflection ๊ธฐ๋ฐ์ผ๋ก ๋์ํ๋ฉฐ ์ด๋ฅผ ํตํด Transaction, AOP, Security ๊ฐ์ ๊ณตํต ๊ธฐ๋ฅ์ ๋น์ฆ๋์ค ๋ก์ง๊ณผ ๋ถ๋ฆฌํฉ๋๋ค.
๋ค๋ง Reflection๊ณผ Proxy ๊ตฌ์กฐ๋ startup ๋น์ฉ ์ฆ๊ฐ์ ์ด์ ๋ณต์ก์ฑ์ ์ ๋ฐํ ์ ์์ต๋๋ค.
๊ด๋ จ CS ๊ฐ๋ ์ฐ๊ฒฐ
- Dynamic Linking
- Runtime System
- Dependency Injection
- AOP
- Proxy Pattern
- Virtual Machine
- Plugin Architecture
ํ์ ์์ ํนํ ์ค์ํ ํฌ์ธํธ
1. Spring ๋ด๋ถ ๊ตฌ์กฐ ์ดํด
๋๋ถ๋ถ Reflection + Proxy ๊ธฐ๋ฐ.
2. self invocation ๋ฌธ์
์ค๋ฌด ์ฅ์ ์์ธ ์์ฃผ ๋จ.
3. startup latency
MSA ํ๊ฒฝ์์ ์ค์.
4. ์ฌ๋ฐฐํฌ Memory Leak
์ด์ ์ฅ์ ํต์ฌ ์์ธ.
ํต์ฌ ์์ฝ
- Java๋ Runtime Dynamic Loading ๊ธฐ๋ฐ
- ClassLoader๋ JVM ํต์ฌ ๋ฉ์ปค๋์ฆ
- ๋ถ๋ชจ ์์ ๋ชจ๋ธ์ JVM ์์ ์ฑ์ ์ํ ๊ตฌ์กฐ
- Spring ๋ด๋ถ๋ Reflection + Proxy ๊ธฐ๋ฐ
- Proxy๋ ๊ณตํต ๊ธฐ๋ฅ ๋ถ๋ฆฌ๋ฅผ ์ํด ์ฌ์ฉ๋๋ค
- self invocation์ ์ค๋ฌด ๋จ๊ณจ ๋ฌธ์
- ClassLoader leak์ ์ค์ ์ด์ ์ฅ์ ์์ธ์ด๋ค