tracemalloc — 메모리 할당 추적

tracemalloc — 메모리 할당 추적

tracemalloc 모듈은 Python이 할당한 메모리 블록을 추적하는 디버그 도구예요. 다음 정보를 제공해요:

  • 객체가 할당된 traceback
  • 파일 이름과 줄 번호별 할당된 메모리 블록 통계: 할당된 메모리 블록의 총 크기, 수, 평균 크기
  • 메모리 누수를 감지하기 위한 두 스냅샷 간의 차이 계산

Python이 할당한 대부분의 메모리 블록을 추적하려면, PYTHONTRACEMALLOC 환경 변수를 1로 설정하거나 -X tracemalloc 명령줄 옵션을 사용해 가능한 한 빨리 모듈을 시작해야 해요. 런타임에 tracemalloc.start() 함수를 호출해 Python 메모리 할당 추적을 시작할 수도 있어요.

출처: Python documentation

본문

기본적으로 할당된 메모리 블록의 trace는 가장 최근 프레임(1 프레임)만 저장해요. 시작 시 25 프레임을 저장하려면 PYTHONTRACEMALLOC 환경 변수를 25로 설정하거나 -X tracemalloc=25 명령줄 옵션을 사용해요.

예제 (Examples)

상위 10개 표시

메모리를 가장 많이 할당하는 10개 파일 표시:

import tracemalloc

tracemalloc.start()

# ... 애플리케이션 실행 ...

snapshot = tracemalloc.take_snapshot()
top_stats = snapshot.statistics('lineno')

print("[ Top 10 ]")
for stat in top_stats[:10]:
    print(stat)

Python 테스트 스위트 출력 예:

[ Top 10 ]
<frozen importlib._bootstrap>:716: size=4855KiB, count=39328, average=126B
...

차이 계산

두 스냅샷을 찍고 차이를 표시해요:

import tracemalloc

tracemalloc.start()
# ... 애플리케이션 시작 ...
snapshot1 = tracemalloc.take_snapshot()
# ... 메모리를 누출하는 함수 호출 ...
snapshot2 = tracemalloc.take_snapshot()

top_stats = snapshot2.compare_to(snapshot1, 'lineno')
print("[ Top 10 differences ]")
for stat in top_stats[:10]:
    print(stat)

시스템에 여유 메모리가 적으면 Snapshot.dump() 메서드로 스냅샷을 디스크에 써서 오프라인으로 분석하고, Snapshot.load() 메서드로 다시 로드할 수 있어요.

메모리 블록의 traceback 가져오기

가장 큰 메모리 블록의 traceback을 표시하는 코드:

import tracemalloc

# 25 프레임 저장
tracemalloc.start(25)

# ... 애플리케이션 실행 ...

snapshot = tracemalloc.take_snapshot()
top_stats = snapshot.statistics('traceback')

# 가장 큰 메모리 블록 선택
stat = top_stats[0]
print("%s memory blocks: %.1f KiB" % (stat.count, stat.size / 1024))
for line in stat.traceback.format():
    print(line)

꽤 예쁜 상위(top)

메모리를 가장 많이 할당하는 10줄을 꽤 예쁘게 표시하는 코드(특정 파일 무시 포함):

import linecache
import tracemalloc

def display_top(snapshot, key_type='lineno', limit=10):
    snapshot = snapshot.filter_traces((
        tracemalloc.Filter(False, "<frozen importlib._bootstrap>"),
        tracemalloc.Filter(False, "<unknown>"),
    ))
    top_stats = snapshot.statistics(key_type)
    ...

get_traced_memory()reset_peak()를 사용하면 합계 계산 후의 작은 메모리 사용량과 계산 중의 최대 메모리 사용량을 모두 관찰할 수 있어요.

API

함수 (Functions)

  • tracemalloc.clear_traces() — Python이 할당한 메모리 블록의 trace를 지워요.
  • tracemalloc.get_object_traceback(obj) — Python 객체 obj가 할당된 traceback을 가져와요. Traceback 인스턴스 또는, tracemalloc 모듈이 메모리 할당을 추적하지 않거나 객체 할당을 추적하지 않았다면 None을 반환해요.
  • tracemalloc.get_traceback_limit() — trace의 traceback에 저장되는 최대 프레임 수를 가져와요.
  • tracemalloc.get_traced_memory() — tracemalloc 모듈이 추적한 메모리 블록의 현재 크기와 최대 크기를 튜플 (current: int, peak: int)로 가져와요.
  • tracemalloc.reset_peak() — tracemalloc 모듈이 추적한 메모리 블록의 최대 크기를 현재 크기로 설정해요. 버전 3.9에서 추가되었어요.
  • tracemalloc.get_tracemalloc_memory() — 메모리 블록의 trace를 저장하는 데 사용된 tracemalloc 모듈의 메모리 사용량(바이트)을 가져와요.
  • tracemalloc.is_tracing() — tracemalloc 모듈이 Python 메모리 할당을 추적 중이면 True, 그렇지 않으면 False.
  • tracemalloc.start(nframe: int = 1) — Python 메모리 할당 추적을 시작해요. 수집된 trace의 traceback은 nframe 프레임으로 제한돼요. 기본 제한은 1이에요. nframe은 1보다 크거나 같아야 해요. 더 많은 프레임을 저장하면 tracemalloc 모듈의 메모리와 CPU 오버헤드가 증가해요.
  • tracemalloc.stop() — Python 메모리 할당 추적을 중지해요. 이전에 수집된 모든 trace도 지워요.
  • tracemalloc.take_snapshot() — Python이 할당한 메모리 블록의 trace 스냅샷을 찍어 새 Snapshot 인스턴스를 반환해요.

DomainFilter

classtracemalloc.DomainFilter(inclusive: bool, domain: int) — 주소 공간(domain)별로 메모리 블록의 trace를 필터링해요. inclusive가 True이면 도메인에 할당된 블록을 일치시키고, False이면 도메인에 할당되지 않은 블록을 일치시켜요.

Filter

classtracemalloc.Filter(inclusive: bool, filename_pattern: str, lineno: int=None, all_frames: bool=False, domain: int=None) — 메모리 블록 trace에 대한 필터예요. filename_pattern의 구문은 fnmatch.fnmatch() 함수를 참고하세요. .pyc 확장자는 .py로 대체돼요.

예:

  • Filter(True, subprocess.__file__) — subprocess 모듈의 trace만 포함
  • Filter(False, tracemalloc.__file__) — tracemalloc 모듈의 trace 제외
  • Filter(False, "<unknown>") — 빈 traceback 제외

주요 속성: domain, inclusive, lineno, filename_pattern, all_frames.

Frame

classtracemalloc.Frame — traceback의 프레임. Traceback 클래스는 Frame 인스턴스의 시퀀스예요. 속성: filename(str), lineno(int).

Snapshot

classtracemalloc.Snapshot — Python이 할당한 메모리 블록 trace의 스냅샷. take_snapshot() 함수가 스냅샷 인스턴스를 만들어요.

  • compare_to(old_snapshot: Snapshot, key_type: str, cumulative: bool=False) — 이전 스냅샷과의 차이를 계산해요.
  • dump(filename) — 스냅샷을 파일에 써요.
  • filter_traces(filters) — 필터된 traces 시퀀스로 새 Snapshot 인스턴스를 만들어요.
  • classmethod load(filename) — 파일에서 스냅샷을 로드해요.
  • statistics(key_type: str, cumulative: bool=False)key_type으로 그룹화된 정렬된 Statistic 인스턴스 목록을 가져와요. key_type'filename', 'lineno', 'traceback'일 수 있어요. cumulative가 True이면 가장 최근 프레임뿐 아니라 trace traceback의 모든 프레임의 크기와 수를 누적해요.
  • traceback_limit — 스냅샷 촬영 시 traceback에 저장된 최대 프레임 수
  • traces — Python이 할당한 모든 메모리 블록의 trace. Trace 인스턴스 시퀀스.

Statistic

classtracemalloc.Statistic — 메모리 할당 통계. Snapshot.statistics()가 Statistic 인스턴스 목록을 반환해요. 속성: count(블록 수), size(총 크기 바이트), traceback(할당된 위치).

StatisticDiff

classtracemalloc.StatisticDiff — 이전과 새 Snapshot 인스턴스 간의 메모리 할당 통계 차이. Snapshot.compare_to()가 반환해요. 속성: count, count_diff, size, size_diff, traceback.

Trace

classtracemalloc.Trace — 메모리 블록의 trace. 속성: domain, size, traceback.

Traceback

classtracemalloc.Traceback — 가장 오래된 프레임에서 가장 최근 프레임까지 정렬된 Frame 인스턴스 시퀀스. traceback은 최소 1 프레임을 포함해요. 프레임을 얻지 못하면 줄 번호 0의 파일 이름 "<unknown>"이 사용돼요.

  • total_nframe — 잘리기 전 traceback을 구성한 총 프레임 수
  • format(limit=None, most_recent_first=False) — traceback을 줄 목록으로 형식화해요. limit이 설정되면 limit이 양수일 때 가장 최근 limit 프레임을, 그렇지 않으면 abs(limit)개 가장 오래된 프레임을 형식화해요. most_recent_first가 True이면 가장 최근 프레임이 먼저 반환돼요.

더 알아보기 (Learn more)