Skip to content

Latest commit

ย 

History

History
128 lines (95 loc) ยท 4 KB

File metadata and controls

128 lines (95 loc) ยท 4 KB

81. ํ”„๋กœ๊ทธ๋žจ์ด ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹๊ณผ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜๋ฅผ ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•ด tracemalloc์„ ์‚ฌ์šฉํ•˜๋ผ

1. ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ

  • 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 ๋Š” ๊ฐ์ฒด ์–ด๋–ป๊ฒŒ ํ• ๋‹น๋๋Š”์ง€๋ฅผ ์•Œ๋ ค์ฃผ์ง€ ์•Š์Œ
        • ํŠน์ • ํด๋ž˜์Šค์— ์†ํ•˜๋Š” ๊ฐ์ฒด๊ฐ€ ์—ฌ๋Ÿฌ ๋‹ค๋ฅธ ๋ฐฉ์‹์— ์˜ํ•ด ํ• ๋‹น๋  ์ˆ˜ ์žˆ์Œ
      • ํ• ๋‹น๋œ ๊ฐ์ฒด ๊ฐœ์ˆ˜๋ฅผ ์•„๋Š” ๊ฒƒ ๋ณด๋‹จ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜์‹œํ‚ค๋Š” ๊ฐ์ฒด์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ์•„๋Š”๊ฒŒ ์ค‘์š”

2. tracemalloc ๋‚ด์žฅ ๋ชจ๋“ˆ

  • 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)