Post

๐Ÿ“‘ JAVA 01 - JAVA ๊ฐ์ฒด ์ƒ์„ฑ ๊ณผ์ •๊ณผ JVM ๋ฉ”๋ชจ๋ฆฌ ๊ตฌ์กฐ ์‹ฌํ™”

๐Ÿ“‘ JAVA 01 - JAVA ๊ฐ์ฒด ์ƒ์„ฑ ๊ณผ์ •๊ณผ JVM ๋ฉ”๋ชจ๋ฆฌ ๊ตฌ์กฐ ์‹ฌํ™”

1์ฃผ์ฐจ 1์ผ์ฐจ - ๊ฐ์ฒด ์ƒ์„ฑ ๊ณผ์ •๊ณผ JVM ๋ฉ”๋ชจ๋ฆฌ ๊ตฌ์กฐ ์‹ฌํ™”

Java ๋ฐฑ์—”๋“œ ๋ฉด์ ‘์—์„œ ๊ต‰์žฅํžˆ ์ž์ฃผ ๋“ฑ์žฅํ•˜๋Š” ์งˆ๋ฌธ:

โ€œnew ํ‚ค์›Œ๋“œ๋กœ ๊ฐ์ฒด ์ƒ์„ฑ ์‹œ ์–ด๋–ค ์ผ์ด ๋ฐœ์ƒํ•˜๋‚˜์š”?โ€

๋งŽ์€ ๊ฒฝ์šฐ:

  • Heap์— ๊ฐ์ฒด ์ƒ์„ฑ
  • Stack์— ์ฐธ์กฐ ์ €์žฅ

์ •๋„๋กœ ๋๋‚œ๋‹ค.

ํ•˜์ง€๋งŒ ์‹ค์ œ ์ค‘๊ฒฌ ์ด์ƒ ๋ฉด์ ‘์—์„œ๋Š”:

  • ํด๋ž˜์Šค ๋กœ๋”ฉ
  • ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น
  • ๊ฐ์ฒด ์ดˆ๊ธฐํ™”
  • ์ฐธ์กฐ ์—ฐ๊ฒฐ
  • GC Root
  • ๊ฐ์ฒด ์ƒ๋ช…์ฃผ๊ธฐ

๊นŒ์ง€ ์—ฐ๊ฒฐํ•ด์„œ ์„ค๋ช…ํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค.

ํŠนํžˆ Spring ๊ธฐ๋ฐ˜ ๋ฐฑ์—”๋“œ์—์„œ๋Š”:

๊ฐ์ฒด ์ƒ์„ฑ ์ž์ฒด๊ฐ€ ์„ฑ๋Šฅ๊ณผ ์ง๊ฒฐ

๋˜๊ธฐ ๋•Œ๋ฌธ์— ๋งค์šฐ ์ค‘์š”ํ•˜๋‹ค.


JVM ๋ฉ”๋ชจ๋ฆฌ ๊ตฌ์กฐ

graph TD

JVM[JVM Memory]

JVM --> MA[Method Area]
JVM --> HEAP[Heap]
JVM --> STACK[Stack]

MA --> MA1[ํด๋ž˜์Šค ์ •๋ณด]
MA --> MA2[static ๋ณ€์ˆ˜]
MA --> MA3[๋Ÿฐํƒ€์ž„ ์ƒ์ˆ˜ ํ’€]

HEAP --> H1[User ๊ฐ์ฒด]
HEAP --> H2[Order ๊ฐ์ฒด]
HEAP --> H3[String ๊ฐ์ฒด]

STACK --> S1[Thread-1 Stack]
STACK --> S2[Thread-2 Stack]

JVM ๋ฉ”๋ชจ๋ฆฌ๋Š” ํฌ๊ฒŒ ๋‹ค์Œ ์˜์—ญ์œผ๋กœ ๋‚˜๋‰œ๋‹ค.

  • Method Area
  • Heap
  • Stack
  • PC Register
  • Native Method Stack

์˜ค๋Š˜ ํ•ต์‹ฌ์€:

  • Heap
  • Stack
  • Method Area

์ดํ•ด๋‹ค.


Heap

Heap์€:

๊ฐ์ฒด๊ฐ€ ์ €์žฅ๋˜๋Š” ๋ฉ”๋ชจ๋ฆฌ ์˜์—ญ

์ด๋‹ค.

์˜ˆ์‹œ:

1
User user = new User();

์‹ค์ œ User ๊ฐ์ฒด๋Š” Heap์— ์ƒ์„ฑ๋œ๋‹ค.


์™œ Heap์€ ๊ณต์œ  ์˜์—ญ์ผ๊นŒ?

graph LR

T1[Thread-1] --> H[Heap์˜ User ๊ฐ์ฒด]
T2[Thread-2] --> H

๋งค์šฐ ์ค‘์š”ํ•œ ์งˆ๋ฌธ.

Heap์€:

์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ๊ฐ€ ๋™์ผ ๊ฐ์ฒด๋ฅผ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค๊ณ„

๋˜์—ˆ๋‹ค.

๋งŒ์•ฝ ์Šค๋ ˆ๋“œ๋ณ„ Heap์„ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด:

  • ๊ฐ์ฒด ๊ณต์œ  ์–ด๋ ค์›€
  • ๋ฉ”๋ชจ๋ฆฌ ๋‚ญ๋น„ ์ฆ๊ฐ€
  • ๊ฐ์ฒด ์ „๋‹ฌ ๋น„์šฉ ์ฆ๊ฐ€

๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

์ฆ‰:

โ€œ๊ฐ์ฒด ๊ณต์œ  ํšจ์œจโ€

์„ ์œ„ํ•ด Heap์€ ๊ณต์œ  ๋ฉ”๋ชจ๋ฆฌ๋กœ ์„ค๊ณ„๋˜์—ˆ๋‹ค.


Stack

Stack์€:

๋ฉ”์„œ๋“œ ํ˜ธ์ถœ๊ณผ ์ง€์—ญ ๋ณ€์ˆ˜ ์ €์žฅ ์˜์—ญ

์ด๋‹ค.

์˜ˆ์‹œ:

1
2
3
public void test() {
    User user = new User();
}

์—ฌ๊ธฐ์„œ:

  • user ๋ณ€์ˆ˜ โ†’ Stack
  • ์‹ค์ œ User ๊ฐ์ฒด โ†’ Heap

์ €์žฅ.


์™œ Stack์€ ์Šค๋ ˆ๋“œ๋ณ„ ๋…๋ฆฝ์ผ๊นŒ?

graph TD

T1[Thread-1 Stack]
T2[Thread-2 Stack]

T1 --> A1[methodA]
T1 --> A2[local variable]

T2 --> B1[methodB]
T2 --> B2[local variable]

์ด์œ :

๋ฉ”์„œ๋“œ ์‹คํ–‰ ํ๋ฆ„ ์ถฉ๋Œ ๋ฐฉ์ง€

๋•Œ๋ฌธ์ด๋‹ค.

๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ์ƒํƒœ๋Š”: ์Šค๋ ˆ๋“œ๋งˆ๋‹ค ๋…๋ฆฝ์ ์ด์–ด์•ผ ํ•œ๋‹ค.

๋”ฐ๋ผ์„œ:

  • ์ง€์—ญ ๋ณ€์ˆ˜
  • ๋งค๊ฐœ๋ณ€์ˆ˜
  • ๋ฐ˜ํ™˜ ์ •๋ณด

๋“ฑ์„ ๋…๋ฆฝ ๊ด€๋ฆฌํ•œ๋‹ค.


Method Area

ํด๋ž˜์Šค ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ์ €์žฅ ์˜์—ญ.

์ €์žฅ ๋Œ€์ƒ:

  • ํด๋ž˜์Šค ์ •๋ณด
  • static ๋ณ€์ˆ˜
  • ๋Ÿฐํƒ€์ž„ ์ƒ์ˆ˜ ํ’€
  • ๋ฉ”์„œ๋“œ ์ •๋ณด

static ๋ณ€์ˆ˜๋Š” ์™œ ๋ณ„๋„ ๊ด€๋ฆฌํ• ๊นŒ?

์˜ˆ์‹œ:

1
static int count = 0;

static์€:

๊ฐ์ฒด๋ณ„ ๋ฐ์ดํ„ฐ๊ฐ€ ์•„๋‹ˆ๋ผ ํด๋ž˜์Šค ๊ณต์šฉ ๋ฐ์ดํ„ฐ

์ด๋‹ค.

๋”ฐ๋ผ์„œ: Heap ๊ฐ์ฒด ๋‚ด๋ถ€๊ฐ€ ์•„๋‹ˆ๋ผ ๋ณ„๋„ ๋ฉ”๋ชจ๋ฆฌ ์˜์—ญ์—์„œ ๊ด€๋ฆฌํ•œ๋‹ค.


๊ฐ์ฒด ์ƒ์„ฑ ๊ณผ์ •

graph TD
A[new User ์‹คํ–‰] --> B[ClassLoader ํ™•์ธ]
B --> C[Heap ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น]
C --> D[๊ธฐ๋ณธ๊ฐ’ ์ดˆ๊ธฐํ™”]
D --> E[์ƒ์„ฑ์ž ํ˜ธ์ถœ]
E --> F[Stack ์ฐธ์กฐ ์ €์žฅ]
F --> G[GC Root ์—ฐ๊ฒฐ]

๋‹ค์Œ ์ฝ”๋“œ ๊ธฐ์ค€์œผ๋กœ ๋ณด์ž.

1
User user = new User();

JVM ๋‚ด๋ถ€์—์„œ๋Š” ๊ฝค ๋งŽ์€ ๊ณผ์ •์ด ๋ฐœ์ƒํ•œ๋‹ค.


1. ํด๋ž˜์Šค ๋กœ๋”ฉ ํ™•์ธ

JVM์€ ๋จผ์ €:

User ํด๋ž˜์Šค๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ์— ์กด์žฌํ•˜๋Š”๊ฐ€?

ํ™•์ธํ•œ๋‹ค.

์—†์œผ๋ฉด:

  • ClassLoader ๋™์ž‘
  • .class ๋กœ๋”ฉ

์ˆ˜ํ–‰.


์™œ ๋Ÿฐํƒ€์ž„ ๋กœ๋”ฉ ๊ตฌ์กฐ์ผ๊นŒ?

Java๋Š”:

Runtime Dynamic Loading

์ง€์› ์–ธ์–ด๋‹ค.

์ฆ‰: ํ•„์š”ํ•œ ์‹œ์ ์— ํด๋ž˜์Šค ๋กœ๋”ฉ ๊ฐ€๋Šฅ.

์žฅ์ :

  • ๋ฉ”๋ชจ๋ฆฌ ํšจ์œจ
  • ์œ ์—ฐ์„ฑ
  • ํ”„๋ ˆ์ž„์›Œํฌ ๊ตฌํ˜„ ์šฉ์ด

2. Heap ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น

๊ฐ์ฒด ์ €์žฅ ๊ณต๊ฐ„ ์ƒ์„ฑ.

์ด๋•Œ:

  • ํ•„๋“œ ๊ธฐ๋ณธ๊ฐ’ ์ดˆ๊ธฐํ™”
  • ๋ฉ”๋ชจ๋ฆฌ ํ™•๋ณด

์ˆ˜ํ–‰.

์˜ˆ์‹œ:

1
2
3
int -> 0
boolean -> false
reference -> null

์™œ ๊ธฐ๋ณธ๊ฐ’ ์ดˆ๊ธฐํ™”๋ฅผ ํ• ๊นŒ?

Java ํ•ต์‹ฌ ์ฒ ํ•™:

โ€œ์•ˆ์ „์„ฑโ€

๋•Œ๋ฌธ์ด๋‹ค.

C/C++์ฒ˜๋Ÿผ: ์“ฐ๋ ˆ๊ธฐ๊ฐ’ ๋…ธ์ถœ ๋ฐฉ์ง€ ๋ชฉ์ .


3. ์ƒ์„ฑ์ž ํ˜ธ์ถœ

์ดํ›„ ์ƒ์„ฑ์ž ์‹คํ–‰.

1
new User();

์ƒ์„ฑ์ž ๋‚ด๋ถ€ ๋กœ์ง ์ˆ˜ํ–‰.


4. ์ฐธ์กฐ ์—ฐ๊ฒฐ

graph LR
S[Stack์˜ user ๋ณ€์ˆ˜] --> H[Heap์˜ User ๊ฐ์ฒด]

์ตœ์ข…์ ์œผ๋กœ:

1
User user

์ฐธ์กฐ ๋ณ€์ˆ˜๊ฐ€ Stack์— ์ƒ์„ฑ๋˜๊ณ : Heap ๊ฐ์ฒด ์ฃผ์†Œ ์ฐธ์กฐ.

๊ตฌ์กฐ:

1
2
Stack
user -----> Heap(User ๊ฐ์ฒด)

GC Root์™€ ๊ฐ์ฒด ์ƒ๋ช…์ฃผ๊ธฐ

Reachable ๊ฐ์ฒด

graph TD
ROOT[GC Root]

ROOT --> USER[User ๊ฐ์ฒด]
USER --> ORDER[Order ๊ฐ์ฒด]

Unreachable ๊ฐ์ฒด

graph TD
ROOT[GC Root]
OBJ[User ๊ฐ์ฒด]

Java GC ํ•ต์‹ฌ ๊ธฐ์ค€:

Reachability(๋„๋‹ฌ ๊ฐ€๋Šฅ์„ฑ)

์ด๋‹ค.


GC Root๋ž€?

๋Œ€ํ‘œ GC Root:

  • Stack ์ง€์—ญ ๋ณ€์ˆ˜
  • static ๋ณ€์ˆ˜
  • JNI ์ฐธ์กฐ

์™œ Reachability ๊ธฐ์ค€์„ ์‚ฌ์šฉํ• ๊นŒ?

๋‹จ์ˆœ ์‹œ๊ฐ„ ๊ธฐ์ค€ ์ œ๊ฑฐ๋Š” ์œ„ํ—˜ํ•˜๋‹ค.

์˜ˆ์‹œ:

1
User user = cache.get();

์˜ค๋ž˜๋œ ๊ฐ์ฒด๋ผ๋„: ์—ฌ์ „ํžˆ ์‚ฌ์šฉ ์ค‘์ผ ์ˆ˜ ์žˆ๋‹ค.

๋”ฐ๋ผ์„œ JVM์€:

โ€œ์ฐธ์กฐ ๊ฐ€๋Šฅ ์—ฌ๋ถ€โ€

๋กœ ํŒ๋‹จํ•œ๋‹ค.


๊ฐ์ฒด๊ฐ€ GC ๋Œ€์ƒ์ด ๋˜๋Š” ๊ณผ์ •

์˜ˆ์‹œ:

1
2
3
public void test() {
    User user = new User();
}

๋ฉ”์„œ๋“œ ์ข…๋ฃŒ ์‹œ:

  • Stack Frame ์ œ๊ฑฐ
  • user ์ฐธ์กฐ ์ œ๊ฑฐ

๋ฐœ์ƒ.

์ดํ›„ Heap ๊ฐ์ฒด๋Š”:

GC Root๋กœ๋ถ€ํ„ฐ ๋„๋‹ฌ ๋ถˆ๊ฐ€๋Šฅ

์ƒํƒœ๊ฐ€ ๋œ๋‹ค.

๊ทธ๋•Œ GC ๋Œ€์ƒ ๊ฐ€๋Šฅ.


์™œ ๊ฐ์ฒด ์ƒ์„ฑ ๋น„์šฉ์ด ์ค‘์š”ํ• ๊นŒ?

graph TD

A[๊ฐ์ฒด ์ƒ์„ฑ ์ฆ๊ฐ€] --> B[Heap ์‚ฌ์šฉ๋Ÿ‰ ์ฆ๊ฐ€]
B --> C[GC ๋นˆ๋„ ์ฆ๊ฐ€]
C --> D[Stop-The-World ์ฆ๊ฐ€]
D --> E[์‘๋‹ต ์ง€์—ฐ ๋ฐœ์ƒ ๊ฐ€๋Šฅ]

Java๋Š” ๊ฐ์ฒด ์ƒ์„ฑ์ด ์‰ฌ์šด ์–ธ์–ด๋‹ค.

ํ•˜์ง€๋งŒ ๋Œ€๊ทœ๋ชจ ํŠธ๋ž˜ํ”ฝ ํ™˜๊ฒฝ์—์„œ๋Š”:

  • ๊ฐ์ฒด ์ƒ์„ฑ ์ฆ๊ฐ€
  • Heap ์‚ฌ์šฉ ์ฆ๊ฐ€
  • GC ์ฆ๊ฐ€
  • STW ์ฆ๊ฐ€

๋กœ ์ด์–ด์งˆ ์ˆ˜ ์žˆ๋‹ค.


์‹ค์ œ ์žฅ์•  ์‚ฌ๋ก€

๋Œ€ํ‘œ ์‚ฌ๋ก€:

  • API ์‘๋‹ต๋งˆ๋‹ค DTO ๊ณผ๋‹ค ์ƒ์„ฑ
  • ๋ฌธ์ž์—ด ๋ฐ˜๋ณต ์ƒ์„ฑ
  • ๋ถˆํ•„์š”ํ•œ ๊ฐ์ฒด ๋ณ€ํ™˜

๊ฒฐ๊ณผ:

  • GC ๊ณผ๋ถ€ํ•˜
  • ์‘๋‹ต ์ง€์—ฐ
  • CPU ์ฆ๊ฐ€

๋ฐœ์ƒ ๊ฐ€๋Šฅ.


์‹ค๋ฌดํ˜• ๊ด€์ 

Spring ์„œ๋ฒ„๋Š”: ์š”์ฒญ๋งˆ๋‹ค ๋งค์šฐ ๋งŽ์€ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

์˜ˆ์‹œ:

  • Request DTO
  • Response DTO
  • Entity
  • ๋กœ๊ทธ ๊ฐ์ฒด

๋”ฐ๋ผ์„œ:

๊ฐ์ฒด ์ƒ์„ฑ๋Ÿ‰ = ์„ฑ๋Šฅ ์˜ํ–ฅ ์š”์†Œ

๊ฐ€ ๋œ๋‹ค.


Trade-off ๊ด€์ 

๊ฐ์ฒด ์ƒ์„ฑ ์žฅ์ 

  • ์ฝ”๋“œ ๋‹จ์ˆœํ™”
  • ๋ถˆ๋ณ€ ๊ฐ์ฒด ํ™œ์šฉ ๊ฐ€๋Šฅ
  • ์•ˆ์ •์„ฑ ์ฆ๊ฐ€

๋‹จ์ 

  • GC ์ฆ๊ฐ€
  • ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ ์ฆ๊ฐ€
  • CPU ๋น„์šฉ ์ฆ๊ฐ€

์ฆ‰:

โ€œ์•ˆ์ •์„ฑ vs ์„ฑ๋Šฅโ€

Trade-off ์กด์žฌ.


๋ฉด์ ‘ ๊ผฌ๋ฆฌ ์งˆ๋ฌธ

์ž์ฃผ ๋‚˜์˜ค๋Š” ์งˆ๋ฌธ:

  • ๊ฐ์ฒด๋Š” ์–ด๋””์— ์ €์žฅ๋˜๋Š”๊ฐ€?
  • Stack๊ณผ Heap ์ฐจ์ด๋Š”?
  • ์™œ Heap์€ ๊ณต์œ  ๋ฉ”๋ชจ๋ฆฌ์ธ๊ฐ€?
  • static ๋ณ€์ˆ˜๋Š” ์–ด๋””์— ์ €์žฅ๋˜๋Š”๊ฐ€?
  • GC Root๋ž€?
  • ์™œ Reachability ๋ฐฉ์‹ ์‚ฌ์šฉํ•˜๋Š”๊ฐ€?
  • ๊ฐ์ฒด ์ƒ์„ฑ ๋น„์šฉ์ด ์™œ ์ค‘์š”ํ•œ๊ฐ€?

์ข‹์€ ๋‹ต๋ณ€ ์˜ˆ์‹œ

graph TD

A[new User ํ˜ธ์ถœ] --> B[ClassLoader ํ™•์ธ]
B --> C[Heap ๊ฐ์ฒด ์ƒ์„ฑ]
C --> D[์ƒ์„ฑ์ž ํ˜ธ์ถœ]
D --> E[Stack ์ฐธ์กฐ ์ €์žฅ]
E --> F[GC Root ์—ฐ๊ฒฐ]
F --> G[์ฐธ์กฐ ์ œ๊ฑฐ ์‹œ GC ๋Œ€์ƒ]

Java์—์„œ ๊ฐ์ฒด ์ƒ์„ฑ ์‹œ ๋จผ์ € ํด๋ž˜์Šค ๋กœ๋”ฉ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. ์ดํ›„ Heap ์˜์—ญ์— ๊ฐ์ฒด ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ• ๋‹นํ•˜๊ณ , ์ƒ์„ฑ์ž๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ์ฐธ์กฐ ๋ณ€์ˆ˜๋Š” Stack์— ์ €์žฅ๋˜๋ฉฐ, ๊ฐ์ฒด๋Š” GC Root๋กœ๋ถ€ํ„ฐ ๋„๋‹ฌ ๋ถˆ๊ฐ€๋Šฅํ•ด์ง€๋ฉด GC ๋Œ€์ƒ์ด ๋ฉ๋‹ˆ๋‹ค.

์ •๋„๊นŒ์ง€ ์„ค๋ช… ๊ฐ€๋Šฅํ•˜๋ฉด ์ƒ๋‹นํžˆ ์ข‹์€ ๋‹ต๋ณ€์ด๋‹ค.


ํ˜„์—…์—์„œ ํŠนํžˆ ์ค‘์š”ํ•œ ํฌ์ธํŠธ

์‹ค๋ฌด์—์„œ๋Š”:

  • ๊ฐ์ฒด ์ƒ์„ฑ๋Ÿ‰
  • GC ๋นˆ๋„
  • ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰

์ด ์„ฑ๋Šฅ๊ณผ ์ง์ ‘ ์—ฐ๊ฒฐ๋œ๋‹ค.

ํŠนํžˆ: ๋Œ€๋Ÿ‰ ํŠธ๋ž˜ํ”ฝ ํ™˜๊ฒฝ์—์„œ๋Š”:

โ€œ๋ถˆํ•„์š”ํ•œ ๊ฐ์ฒด ์ƒ์„ฑ ์ค„์ด๊ธฐโ€

๊ฐ€ ์„ฑ๋Šฅ ์ตœ์ ํ™” ํ•ต์‹ฌ ์ค‘ ํ•˜๋‚˜๋‹ค.


ํ•ต์‹ฌ ์š”์•ฝ

ํ•ต์‹ฌ์€ ๋‹ค์Œ์ด๋‹ค.

  • ๊ฐ์ฒด๋Š” Heap์— ์ €์žฅ๋œ๋‹ค
  • ์ฐธ์กฐ ๋ณ€์ˆ˜๋Š” Stack์— ์ €์žฅ๋œ๋‹ค
  • static์€ Method Area์— ์ €์žฅ๋œ๋‹ค
  • GC๋Š” Reachability ๊ธฐ๋ฐ˜์œผ๋กœ ๋™์ž‘ํ•œ๋‹ค
  • ๊ฐ์ฒด ์ƒ์„ฑ๋Ÿ‰์€ ์„ฑ๋Šฅ๊ณผ ์ง๊ฒฐ๋œ๋‹ค

ํŠนํžˆ ์ค‘์š”ํ•œ ๊ฑด:

โ€œ๊ฐ์ฒด ์ƒ์„ฑ โ†’ ๋ฉ”๋ชจ๋ฆฌ โ†’ GC โ†’ ์„ฑ๋Šฅโ€

ํ๋ฆ„์„ ์—ฐ๊ฒฐํ•ด์„œ ์ดํ•ดํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

This post is licensed under CC BY 4.0 by the author.