81. ํ๋ก๊ทธ๋จ์ด ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ์๊ณผ ๋ฉ๋ชจ๋ฆฌ ๋์๋ฅผ ์ดํดํ๊ธฐ ์ํด tracemalloc์ ์ฌ์ฉํ๋ผ
-
CPython ์ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ๋ฅผ ์ํด reference counting ์ฌ์ฉ
- ๊ฐ์ฒด๋ฅผ ๊ฐ๋ฆฌํค๋ ์ฐธ์กฐ๊ฐ ๋ชจ๋ ์์ด์ง๋ฉด ์ฐธ์กฐ๋ ๊ฐ์ฒด๋ ๋ฉ๋ชจ๋ฆฌ์์ ์ญ์ ๋๊ณ ๋ฉ๋ชจ๋ฆฌ ๊ณต๊ฐ์ ๋ค๋ฅธ ๋ฐ์ดํฐ์ ๋ด์ด์ค ์ ์์
- cycle detector ์กด์ฌ, ์๊ธฐ ์์ ์ ์ฐธ์กฐํ๋ ๊ฐ์ฒด์ ๋ฉ๋ชจ๋ฆฌ๋ garbage collect ๋จ
-
CPython ๋ฐํ์์ด ์์์ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ๋ฅผ ํด์ฃผ์ง๋ง ๋ ์ด์ ์ฌ์ฉํ์ง ์๋ ์ธ๋ชจ์๋ ์ฐธ์กฐ๋ฅผ ์ ์งํ๋ ค ํ๋ฏ๋ก ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์์งํ๊ฒ ๋๋ ๊ฒฝ์ฐ ์กด์ฌ
-
๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ ๋๋ฒ๊น ํ๋ ๋ฐฉ๋ฒ
gc๋ด์ฅ ๋ชจ๋์ ์ฌ์ฉํด ํ์ฌ garbage collector ๊ฐ ์๊ณ ์๋ ๋ชจ๋ ๊ฐ์ฒด ๋์ดgc๋ด์ฅ ๋ชจ๋์ ์ฌ์ฉํด ์คํ ์ค ์์ฑํ ๊ฐ์ฒด ๊ฐ์์ ์์ฑํ ๊ฐ์ฒด ์ค ์ผ๋ถ๋ฅผ ์ถ๋ ฅ
# waste_memory.py import os class MyObject: def __init__(self): self.data = os.urandom(100) def get_data(): values = [] for _ in range(100): obj = MyObject() values.append(obj) return values def run(): deep_values = [] for _ in range(100): deep_values.append(get_data()) return deep_values
# using_gc.py import gc found_objects = gc.get_objects() print('์ด์ :', len(found_objects)) import waste_memory hold_reference = waste_memory.run() found_objects = gc.get_objects() print('์ดํ:', len(found_objects)) for obj in found_objects[:3]: print(repr(obj)[:100]) >>> ์ด์ : 6207 ์ดํ: 16801 <waste_memory.MyObject object at 0x10390aeb8> <waste_memory.MyObject object at 0x10390aef0> <waste_memory.MyObject object at 0x10390af28> ...
- ๋ฌธ์
gc.get_objects๋ ๊ฐ์ฒด ์ด๋ป๊ฒ ํ ๋น๋๋์ง๋ฅผ ์๋ ค์ฃผ์ง ์์- ํน์ ํด๋์ค์ ์ํ๋ ๊ฐ์ฒด๊ฐ ์ฌ๋ฌ ๋ค๋ฅธ ๋ฐฉ์์ ์ํด ํ ๋น๋ ์ ์์
- ํ ๋น๋ ๊ฐ์ฒด ๊ฐ์๋ฅผ ์๋ ๊ฒ ๋ณด๋จ ๋ฉ๋ชจ๋ฆฌ ๋์์ํค๋ ๊ฐ์ฒด์ ๋ํ ์ ๋ณด๋ฅผ ์๋๊ฒ ์ค์
- python 3.4 ๋ถํฐ ๋์
- ๊ฐ์ฒด๋ฅผ ์์ ์ด ํ ๋น๋ ์ฅ์์ ์ฐ๊ฒฐ
- ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ์ ์ด์ ๊ณผ ์ดํ ์ค๋ ์ท์ ๋ง๋ค์ด ๋น๊ต
# top_n.py
import tracemalloc
tracemalloc.start(10) # ์คํ ๊น์ด ์ค์
time1 = tracemalloc.take_snapshot() # ์ด์ ์ค๋
์ท
import waste_memory
x = waste_memory.run() # ์ด ๋ถ๋ถ์ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ์ ๋๋ฒ๊น
ํจ
time2 = tracemalloc.take_snapshot() # ์ดํ ์ค๋
์ท
stats = time2.compare_to(time1, 'lineno') # ๋ ์ค๋
์ท์ ๋น๊ต
for stat in stats[:3]:
print(stat)
>>>
waste_memory.py:5: size=2392 KiB (+2392 KiB), count=29994 (+29994), average=82 B
waste_memory.py:10: size=547 KiB (+547 KiB), count=10001 (+10001), average=56 B
waste_memory.py:11: size=82.8 KiB (+82.8 KiB), count=100 (+100), average=848 B-
์ถ๋ ฅ์ ํตํด ํฌ๊ธฐ์ ์นด์ดํธ ๋ ์ด๋ธ ํ์ธํด๋ณด๋ฉด ํ๋ก๊ทธ๋จ์์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ฃผ๋ก ์ฌ์ฉํ๋ ๊ฐ์ฒด์ ์ด๋ฐ ๊ฐ์ฒด๋ฅผ ํ ๋นํ ์์ค ์ฝ๋๋ฅผ ๋ช ํํ ์ ์ ์์
-
tracemalloc๋ชจ๋์ ๊ฐ ํ ๋น์ ์ ์ฒด stacktrace ์ ๊ณต
# with_trace.py
import tracemalloc
tracemalloc.start(10)
time1 = tracemalloc.take_snapshot()
import waste_memory
x = waste_memory.run()
time2 = tracemalloc.take_snapshot()
stats = time2.compare_to(time1, 'traceback')
top = stats[0]
print('๊ฐ์ฅ ๋ง์ด ์ฌ์ฉํ๋ ๋ถ๋ถ์:')
print('\n'.join(top.traceback.format()))
>>>
๊ฐ์ฅ ๋ง์ด ์ฌ์ฉํ๋ ๋ถ๋ถ์:
File "with_trace.py", line 9
x = waste_memory.run()
File "waste_memory.py", line 17
deep_values.append(get_data())
File "waste_memory.py", line 10
obj = MyObject()
File "waste_memory.py", line 5
self.data = os.urandom(100)