4 minute read

โ€œ@Backend OO๋‹˜, ํž™ ๋คํ”„ ๋œฐ ์ค„ ์•Œ์ฃ ?โ€

๋“ค์–ด๊ฐ€๋ฉฐโ€ฆ

์„œ๋ฒ„๊ฐ€ ์•Œ ์ˆ˜ ์—†๋Š” ์ด์œ ๋กœ ๊ฐ‘์ž๊ธฐ ์ฃฝ๊ฑฐ๋‚˜ ์„ฑ๋Šฅ์ด ์ €ํ•˜๋˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์ข…์ข… ์žˆ๋Š”๋ฐ,

๋ณดํ†ต heap memory ๋‚ด์—์„œ memory leak ์ด ์›์ธ์ธ ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๋‹ค.

๋ณด๋‹ค ์ •๋ฐ€ํ•˜๊ฒŒ ๋ถ„์„ํ•ด์„œ ํ•ด๊ฒฐํ•˜๋ ค๋ฉด heap dump ๋ฅผ ๋– ์„œ ํ™•์ธํ•ด๋ณด์•„์•ผ ํ•˜๋Š”๋ฐ,

์ด์ „์— ๊ด€๋ จ ๊ฒฝํ—˜์ด ์—†๋‹ค๋ฉด heapdump ๋ฅผ ๋œจ๋‹ค. ๋ผ๋Š” ๋ง ์ž์ฒด๊ฐ€ ์ƒ์†Œํ•  ์ˆ˜ ๋ฐ–์— ์—†๋‹ค.

๋ณธ ํฌ์ŠคํŒ…์—์„œ heapdump ๋ฅผ ๋– ๋ณด๋Š” ํ–‰์œ„ ๋ฅผ ํ•œ ์‚ฌ์ดํด ํ•ด๋ณด๋ฉด์„œ.. ๊ฐ€๋ณ๊ฒŒ ๋Š๋‚Œ์„ ์žก์•„๋ณด๋„๋ก ํ•˜์ž.

๋‹นํ™ฉํ•˜์ง€ ์•Š์„ ๋ฏธ๋ž˜์˜ ์ž์‹ ์„ ์œ„ํ•ด..!


์‚ฌ์ด๋“œ ํ”„๋กœ์ ํŠธ๋กœ ํ•œ๋ฒˆ ์‹ค์Šตํ•ด๋ณด์ž~!

ํ˜„์žฌ ์ง„ํ–‰์ค‘์ธ ์‚ฌ์ด๋“œ ํ”„๋กœ์ ํŠธ์—์„œ ์‚ฌ์šฉ๋˜๋Š” Spring boot application ์€ jib tool ์„ ์ด์šฉํ•˜์—ฌ, docker container ํ™˜๊ฒฝ์—์„œ ๋ฐฐํฌํ•˜๊ณ  ์žˆ๋‹ค.

์ด์™€ ๊ฐ™์€ ํ™˜๊ฒฝ์—์„œ heap dump ๋Š” ์–ด๋–ป๊ฒŒ ์ƒ์„ฑํ•˜๋Š” ์ง€ ์ง€๊ธˆ ๋ฐ”๋กœ ๊ฐ„๋‹จํ•˜๊ฒŒ ์•Œ์•„๋ด…์‹œ๋‹ค!~

Heap-dump

heap dump ๋ถ„์„์„ ํ†ตํ•ด Java application ์˜ ์„ฑ๋Šฅ ๋ถ„์„์„ ์‰ฝ๊ฒŒ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์„œ heap dump ์ด๋ž€, heap memory ์— ๋Œ€ํ•œ snapshot ์œผ๋กœ

memory leak ์ด๋‚˜ ๊ธฐํƒ€ ๋‹ค๋ฅธ ๋ฌธ์ œ๋ฅผ ์ง„๋‹จํ•˜๋Š” ๋ฐ์— ํฐ ๋‹จ์„œ๋ฅผ ์ œ๊ณตํ•ด์ค๋‹ˆ๋‹ค.

์ด์ „์— ์‚ฌ์ด๋“œ ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋ฉฐ ์ž๊พธ ec2 ์„œ๋ฒ„๊ฐ€ OOM (OutOfMemory) ์—๋Ÿฌ ๋กœ๊ทธ๋ฅผ ๋„์šฐ๋ฉฐ ์ฃฝ๋Š” ๊ฒฝํ—˜์„ ํ–ˆ์—ˆ๋Š”๋ฐ

๊ทธ ๋‹น์‹œ์— heap dump ์— ๋Œ€ํ•ด์„œ ์•Œ๊ณ  ์žˆ์—ˆ๋”๋ผ๋ฉด

์กฐ๊ธˆ ๋” ์‰ฝ๊ฒŒ ๋ฌธ์ œ๋ฅผ ์ง„๋‹จํ•˜๊ณ  ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์ง€ ์•Š์•˜์„๊นŒ.. ํ•˜๋Š” ์•„์‰ฌ์›€์ด ์žˆ์Šต๋‹ˆ๋‹ค.

์—ฌํŠผ, heap dump ๋ฅผ ํ™œ์šฉํ•˜๋ฉด memory leak ์— ์˜ํ•œ ์„œ๋ฒ„ ์žฅ์• ๊ฐ€ ๋ฐœ์ƒํ•ด๋„ ํฌ๊ฒŒ ๋‹นํ™ฉํ•˜์ง€ ์•Š๊ณ  ์›์ธ์„ ๋ถ„์„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ธฐ๋ณธ์ ์œผ๋กœ OutOfMemory ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด, ์‚ฌ์ „์— ์ง€์ •ํ•ด๋‘” path ์— heap dump ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜๋„๋ก ํ•ด๋‘๋Š” ๊ฒƒ์ด ๋งˆ์Œ ํŽธํ•œ ๋ฐฉ๋ฒ•์ธ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ด๋ฅผ ์œ„ํ•ด์„œ JVM option ์„ ์ฃผ๋ฉด ๋˜๋Š”๋ฐ,

์‚ฌ์ด๋“œ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” jib ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์œผ๋ฏ€๋กœ

์•„๋ž˜์™€ ๊ฐ™์ด jvmFlag ๋ฅผ ์ง€์ •ํ•ด์„œ, OOM ๋ฐœ์ƒ ์‹œ ์ง€์ •๋œ ๊ฒฝ๋กœ์— heapdump ๊ฐ€ ์ƒ์„ฑ๋  ์ˆ˜ ์žˆ๋„๋ก ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฐ์ž์˜ ํ”„๋กœ์ ํŠธ ํ™˜๊ฒฝ์— ๋งž์ถฐ์„œ ์„ค์ •ํ•ด์•ผ ํ•˜๋ฏ€๋กœ ์ฐธ๊ณ ์šฉ์œผ๋กœ๋งŒ ๋ณด๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค!

jib {
	from {
		image = "openjdk:17"
	}
	to {
		image = "your docker image"
		tags = ["latest"]
	}
	container {
		...
		jvmFlags = [ ... your jvm option ... ,  "-XX:+HeapDumpOnOutOfMemoryError", "-XX:HeapDumpPath=/your-path/your-heap-dump-file-name.hprof"]
		...
	}
}

docker file ์„ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด, ์•„๋ž˜์™€ ๊ฐ™์ด ํ•ด์ค„ ์ˆ˜ ์žˆ๊ฒ ๋„ค์š”!

FROM openjdk:17
...
CMD ["java", "-XX:+HeapDumpOnOutOfMemoryError", "-XX:HeapDumpPath=/path/to/heapdump.hprof", "-jar", "myapp.jar"]

์‚ฌ์‹ค ์ด๋ ‡๊ฒŒํ•˜๋ฉด heapdump ์˜ ํŒŒ์ผ๊ฒฝ๋กœ๊ฐ€ ์–ธ์ œ๋‚˜ ๋™์ผํ•˜๋ฏ€๋กœ, overwrite ๋œ๋‹ค๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ ๋ณดํ†ต์€ ๋‚ ์งœ๋ฅผ ์ด์šฉํ•ด์„œ, OOM ์ด ๋ฐœ์ƒํ•œ ์‹œ์ ์˜ ๋‚ ์งœ๋กœ heapdump ํŒŒ์ผ์˜ ์ด๋ฆ„์„ ์ง€์ •ํ•ด์„œ

heapdump ํŒŒ์ผ๋“ค์˜ ํžˆ์Šคํ† ๋ฆฌ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ์ œ๊ฐ€ ์šด์šฉ์ค‘์ธ ์‚ฌ์ด๋“œ ํ”„๋กœ์ ํŠธ์˜ ec2 ์‚ฌ์–‘์€ t2.micro ์ด๊ณ ..

heapdump ํŒŒ์ผ์˜ ์šฉ๋Ÿ‰์ด ์ž‘์ง€ ์•Š์€ ํŽธ์ด๋ฏ€๋กœ

๋งค๋ฒˆ overwrite ๋˜๋„๋ก ์„ค์ •ํ•ด๋‘์—ˆ์Šต๋‹ˆ๋‹ค.

์—ฌํŠผ, ์œ„์™€ ๊ฐ™์ด JVM ์˜ต์…˜์„ ์ฃผ๋ฉด

OOM ์ด ๋ฐœ์ƒํ•˜๋ฉด ์šฐ๋ฆฌ๊ฐ€ ์ง€์ •ํ•ด๋‘” ๊ฒฝ๋กœ์— heapdump ํŒŒ์ผ์ด ์ž๋™์œผ๋กœ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.

heapdump ํŒŒ์ผ์€ ๋ณดํ†ต eclips memory analysis tool(MAT) ๋ฅผ ์ด์šฉํ•ด์„œ ์‹œ๊ฐ์ ์œผ๋กœ ๋ถ„์„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


Heap dump ์ˆ˜๋™์œผ๋กœ ์ƒ์„ฑํ•˜๊ธฐ

์œ„์™€ ๊ฐ™์ด jvm option ์„ ์ฃผ๋ฉด OOM ๋ฐœ์ƒ ์‹œ heap dump ํŒŒ์ผ์ด ์ง€์ •๋œ ๊ฒฝ๋กœ์— ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.

๋งŒ์•ฝ, ์ˆ˜๋™์œผ๋กœ ์ƒ์„ฑํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์–ด๋–ป๊ฒŒ ํ• ๊นŒ์š”?

๋ณดํ†ต jmap ์„ ์ด์šฉํ•˜์—ฌ heap dump ๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, java app ์˜ pid ๊ฐ€ 1111 ์ด๋ผ๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ๋ช…๋ น์–ด๋ฅผ ์ž…๋ ฅํ•˜์—ฌ heapdump file ์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

jmap -dump:live,format=b,file=heapdump.hprof 1111
  • jmap ๋ช…๋ น์–ด๋Š” ์‹คํ–‰์ค‘์ธ java process ์— ๋ถ€ํ•˜๋ฅผ ์ค„ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, production ์—์„œ๋Š” ์ฃผ์˜ํ•ด์ฃผ์„ธ์š”!
  • ๋งŒ์•ฝ jmap ๋ช…๋ น์–ด๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ์—๋Š” jcmd ๋ช…๋ น์–ด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ heapdump ๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    • jcmd 1111 GC.heap_dump heapdump.hprof
    • ํ™•์ธํ•ด๋ณด๋‹ˆ jmap ๋ณด๋‹ค jcmd ๊ฐ€ ์กฐ๊ธˆ ๋” ์„ฑ๋Šฅ์ ์œผ๋กœ ์šฐ์ˆ˜ํ•˜๋‹ค๊ณ  ํ•˜๋‹ˆ, jcmd ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์„ ๊ฒƒ ๊ฐ™๋„ค์š”!

java app ์ด docker container ๋‚ด์—์„œ ๋™์ž‘ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋” ์ผ๋ฐ˜์ ์ผํ…๋ฐ,

์ด๋•Œ๋Š” ํ•ด๋‹น container ๋‚ด๋ถ€์— ๋จผ์ € ์ ‘๊ทผํ•ด์•ผ๊ฒ ์ฃ ..!

docker ps

๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด ์‹คํ–‰์ค‘์ธ Spring app ์˜ container id ๋ฅผ ์•Œ์•„๋‚ธ ๋‹ค์Œ

docker exec -it [your-container-id] bash

๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด ์ปจํ…Œ์ด๋„ˆ์— bash ํ„ฐ๋ฏธ๋„๋กœ ๋ถ™์–ด์ค์‹œ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ํ•ด๋‹น ์ปจํ…Œ์ด๋„ˆ์—์„œ ๋™์ž‘ํ•˜๊ณ  ์žˆ๋Š” java app ์˜ pid ๋ฅผ ์•Œ์•„๋‚ด์•ผ ํ•˜๋Š”๋ฐ์š”,

ps -ef | grep java

๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด heapdump ๋ฅผ ๋œจ๊ณ ์ž ํ•˜๋Š” java app ์˜ pid ๋ฅผ ์–ป์–ด๋ƒ…์‹œ๋‹ค.

๋งŒ์•ฝ ํ•ด๋‹น ์ปจํ…Œ์ด๋„ˆ์—์„œ ps ๋ช…๋ น์–ด๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด (์‚ฌ์‹ค ๋Œ€๋ถ€๋ถ„ baseimage ๊ฐ€ jdk ์ผํ…Œ๋‹ˆ.. ์ง€์› ์•ˆํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์„ ๊ฒƒ ๊ฐ™๋„ค์š”.)

jps -l

๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด ์‹คํ–‰์ค‘์ธ java app ์˜ pid ๋ฆฌ์ŠคํŠธ๋ฅผ ์กฐํšŒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


container to ec2-host

๋„์ปค ์ปจํ…Œ์ด๋„ˆ ๋‚ด์— ์ƒ์„ฑ๋œ heapdump file ์„ host ๋กœ ์˜ฎ๊ฒจ์•ผ๊ฒ ์ฃ !?

์ด๋ฅผ ์œ„ํ•ด์„œ๋Š” ์•„๋ž˜์˜ ๋ช…๋ น์–ด๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

docker cp mycontainer:/heapdump.hprof to-directory

์˜ˆ๋ฅผ ๋“ค์–ด

docker cp mycontainer:/heapdump.hprof .

๋ผ๊ณ  ์ž…๋ ฅํ•œ ๋’ค์— exit ๋ฅผ ํ†ตํ•ด container ๋ฐ”๊นฅ์œผ๋กœ ๋‚˜๊ฐ€๊ณ  root directory ๋กœ ๊ฐ€๋ณด๋ฉด heapdump.hprof ํŒŒ์ผ์ด ์žˆ์„ ๊ฒ๋‹ˆ๋‹ค!

ec2-host to local

์ด์ œ ec2 ์— ์žˆ๋Š” heapdump ํŒŒ์ผ์„ ๋กœ์ปฌ ์ปดํ“จํ„ฐ๋กœ ์˜ฎ๊ฒจ์ฃผ์–ด์•ผํ•ฉ๋‹ˆ๋‹ค.

๋ณดํ†ต scp ๋ช…๋ น์–ด๋ฅผ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

scp -i [your-pem-key-file-path] [your-ec2-user-name]@[your-ec2-ip-address]:[heapdump-file-path] [to-file-path]

๋งŒ์•ฝ, ์œ„ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๋„์ค‘์—

scp: remote open "/heapdump.hprof": Permission denied

์™€ ๊ฐ™์€ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค๋ฉด

heapdump.hprof ์˜ ๊ถŒํ•œ์„ ํ™•์ธํ•˜๊ณ  ํ•„์š” ์‹œ ์กฐ์ •ํ•ด์ค์‹œ๋‹ค.

์˜ˆ์‹œ๋กœ,

์•„๋ž˜ ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด heapdump.hprof ์— ๋Œ€ํ•œ rw ๊ถŒํ•œ์„ ๋ชจ๋“  ์‚ฌ์šฉ์ž๋กœ๋ถ€ํ„ฐ ํ—ˆ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

sudo chmod 644 /path/to/heapdump.hprof

์ด์ œ ๋‹ค์‹œ ํŒŒ์ผ ์ „์†ก์„ ํ•˜๋ฉด ์›ํ™œํ•˜๊ฒŒ ๋  ๊ฒƒ ์ž…๋‹ˆ๋‹ค ใ…Ž_ใ…Ž

์•„, ๊ทธ๋Ÿฐ๋ฐ ํ•˜๋‚˜ ๊ถ๊ธˆ์ฆ์ด ์ƒ๊ธธ ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™์•„์š”.

์ง€๊ธˆ ์šฐ๋ฆฌ๋Š” ๋„์ปค ์ปจํ…Œ์ด๋„ˆ ๋‚ด๋ถ€์— ์ƒ์„ฑ๋œ ํž™ ๋คํ”„๋ฅผ ๋กœ์ปฌ์— ์˜ฎ๊ธฐ๋ ค๊ณ  ec2 ๋ฅผ ์ค‘๊ฐ„ ๋‹ค๋ฆฌ๋กœ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์ฃ ..?

๋„์ปค ์ปจํ…Œ์ด๋„ˆ์—์„œ ๋กœ์ปฌ๋กœ ๋ฐ”๋กœ ์ „์†กํ•˜์ง€ ์•Š๊ณ , ์™œ ec2 ์— ๊ฐ”๋‹ค๊ฐ€ ๋กœ์ปฌ๋กœ ์ „์†กํ•˜๊ณ  ์žˆ๋Š”๊ฑธ๊นŒ์š”?

๋„์ปค์˜ ๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ธ ์›์น™์ด ๋ฐ”๋กœ ๊ฒฉ๋ฆฌ์„ฑ์ด์ฃ !?

host system ์„ ๊ฑฐ์ณ์„œ local ์œผ๋กœ ํŒŒ์ผ์„ ์ „์†กํ•˜๋Š” ๊ฒƒ์€ ๋„์ปค์˜ ๊ธฐ๋ณธ ์›์น™์ธ ๊ฒฉ๋ฆฌ์„ฑ์„ ์ค€์ˆ˜ํ•˜๋ฉด์„œ๋„,

๋ณด์•ˆ์ ์œผ๋กœ ์•ˆ์ „ํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

๋„์ปค ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์ง์ ‘์ ์œผ๋กœ ์™ธ๋ถ€ ๋„คํŠธ์›Œํฌ์— ๋…ธ์ถœ์‹œํ‚ค๋Š” ๊ฒƒ์€ ๊ฒฉ๋ฆฌ์„ฑ๋„ ์œ„๋ฐฐํ•˜๊ณ , ๋ณด์•ˆ์ ์œผ๋กœ ์ข‹์ง€ ์•Š์•„์š”.

eclipse-MAT

์ด์ œ ์ƒ์„ฑ๋œ heapdump ํŒŒ์ผ์„ eclipse-MAT ์œผ๋กœ ์—ด์–ด๋ด…์‹œ๋‹ค~!

image

image


Java heapdump ๋ถ„์„์„ ํ†ตํ•ด, Java app ์˜ ์„ฑ๋Šฅ์„ ์ตœ์ ํ™”ํ•˜๊ณ  memory leak ๋“ฑ์˜ ์น˜๋ช…์ ์ธ ๋ฌธ์ œ๋ฅผ ์ง„๋‹จํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ณธ ํฌ์ŠคํŒ…์—์„œ๋Š” ๊ฐ„๋‹จํžˆ heapdump ๊ฐ€ ๋ฌด์—‡์ธ์ง€, ์–ด๋–ป๊ฒŒ ์ƒ์„ฑํ•˜๊ณ  ์—ด์–ด๋ณด๋Š”์ง€๋ฅผ ํ™•์ธํ•ด๋ณด์•˜๋Š”๋ฐ์š”

์‹œ๊ฐ„์ด ๋ถ€์กฑํ•œ ๊ด€๊ณ„๋กœโ€ฆ ๐Ÿฅฒ

heapdump ๋ถ„์„์— ๊ด€ํ•ด์„œ๋Š” ํ›„์†๊ธ€์—์„œ ๊ณ„์† ์ง„ํ–‰ํ•˜๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

ํ˜น์‹œ ์ž˜๋ชป๋œ ๋ถ€๋ถ„์„ ๋ฐœ๊ฒฌํ•˜์‹ ๋‹ค๋ฉด ์ฝ”๋ฉ˜ํŠธ ๋‚จ๊ฒจ์ฃผ์„ธ์š”! ๐Ÿ™‡โ€โ™‚๏ธ

Leave a comment