본문 바로가기
Artificial Intelligence/60. Python

[PYTHON] sys.getsizeof가 메모리 할당량을 정확히 측정 못하는 3가지 이유와 해결 방법

by Papa Martino V 2026. 4. 22.
728x90

sys.getsizeof
sys.getsizeof

 

 

파이썬으로 대규모 데이터를 다루는 개발자라면 한 번쯤 sys.getsizeof()를 사용하여 객체의 메모리 점유율을 확인해 보았을 것입니다. 하지만 이 함수가 반환하는 숫자를 그대로 믿었다가는 실제 시스템의 Memory Overflow를 막지 못하는 낭패를 볼 수 있습니다. 왜 sys.getsizeof()는 우리에게 '거짓말'을 하는 것일까요? 본 포스팅에서는 파이썬 객체 관리의 내부 구조(CPython Internals)를 통해 그 이유를 분석하고, 실무에서 정확한 메모리를 측정하는 7가지 해결책을 제시합니다.


1. sys.getsizeof가 부정확한 결정적인 이유

파이썬의 sys.getsizeof()는 객체 자체에 할당된 메모리 크기만을 바이트(Byte) 단위로 반환합니다. 여기서 '자체'라는 단어에 주목해야 합니다. 파이썬은 모든 것이 객체이며, 복합 객체(리스트, 딕셔너리, 클래스 인스턴스 등)는 다른 객체에 대한 참조(Reference)를 담고 있습니다.

특성 sys.getsizeof() 실제 메모리 소비 (Recursive)
측정 범위 직접적인 객체 컨테이너 크기 참조된 모든 하위 객체 포함
참조 처리 포인터 크기(8바이트)만 계산 포인터가 가리키는 실제 데이터 계산
가비지 컬렉션 GC 오버헤드 무시 GC 관리 정보 포함
컨테이너(List 등) 비어있는 슬롯 포함 크기 실제 담긴 아이템들의 총합

예를 들어, 100만 개의 정수가 담긴 리스트에서 sys.getsizeof()를 호출하면 '포인터 100만 개'의 크기만 알려줄 뿐, 정수 객체 100만 개가 실제로 차지하는 메모리는 계산에서 제외됩니다. 이것이 바로 우리가 체감하는 메모리 사용량과 함수 반환값 사이에 큰 차이가 발생하는 근본적인 원인입니다.


2. 실무에서 메모리 측정 문제를 해결하는 7가지 방법 (Example)

개발자가 실무 환경에서 객체의 "진짜" 크기를 파악하고 성능 저하를 방지하기 위해 즉시 적용할 수 있는 코드 예제입니다.

Example 1: 재귀적 메모리 측정 함수 구현 (Deep GetSize)

컨테이너 내부의 모든 객체를 순회하며 실제 크기를 합산하는 고전적이지만 확실한 방법입니다.

import sys

def get_deep_size(obj, seen=None):
    size = sys.getsizeof(obj)
    if seen is None:
        seen = set()
    obj_id = id(obj)
    if obj_id in seen:
        return 0
    seen.add(obj_id)

    if isinstance(obj, dict):
        size += sum([get_deep_size(v, seen) for v in obj.values()])
        size += sum([get_deep_size(k, seen) for k in obj.keys()])
    elif hasattr(obj, '__dict__'):
        size += get_deep_size(obj.__dict__, seen)
    elif hasattr(obj, '__iter__') and not isinstance(obj, (str, bytes, bytearray)):
        size += sum([get_deep_size(i, seen) for i in obj])
    return size

# 테스트
large_list = [[i for i in range(100)] for _ in range(100)]
print(f"Standard size: {sys.getsizeof(large_list)}")
print(f"Deep size: {get_deep_size(large_list)}")
    

Example 2: Pympler 라이브러리를 활용한 전문 측정

직접 코드를 짜는 대신, 파이썬 메모리 프로파일링 표준 라이브러리인 asizeof를 사용합니다.

# pip install pympler
from pympler import asizeof

data = {"key1": [1, 2, 3], "key2": {"inner": "value"}}
real_size = asizeof.asizeof(data)

print(f"객체의 실제 총 메모리 점유량: {real_size} bytes")
    

Example 3: slots을 이용한 클래스 인스턴스 메모리 해결

sys.getsizeof가 크게 측정되는 원인 중 하나인 __dict__(해시 테이블) 생성을 억제하여 메모리를 절약합니다.

class OptimizedUser:
    __slots__ = ['name', 'age']
    def __init__(self, name, age):
        self.name = name
        self.age = age

# __slots__를 사용하면 객체마다 dict를 생성하지 않아 수천만 개 생성 시 메모리 차이가 큼
user = OptimizedUser("Alice", 30)
print(f"Slots 적용 객체 크기: {sys.getsizeof(user)}")
    

Example 4: NumPy 배열의 실제 메모리 데이터 확인

NumPy 배열은 sys.getsizeof 대신 내장 속성인 nbytes를 사용해야 실제 할당량을 정확히 알 수 있습니다.

import numpy as np

arr = np.ones((1000, 1000))
# sys.getsizeof(arr)은 배열 객체 자체의 헤더 크기 위주로 반환
print(f"NumPy 실제 데이터 크기: {arr.nbytes} bytes")
    

Example 5: objgraph로 메모리 누수 객체 추적하기

특정 객체가 왜 메모리를 많이 차지하는지, 어떤 객체들이 참조하고 있는지 시각적으로 확인합니다.

# pip install objgraph
import objgraph

x = [1, 2, 3]
y = [x, dict(key=x)]

objgraph.show_refs([y], filename='sample-graph.png')
# 어떤 객체가 가장 많이 생성되었는지 확인
objgraph.show_most_common_types()
    

Example 6: tracemalloc으로 라인별 메모리 할당량 차이 추적

특정 시점 사이의 메모리 할당 변화를 측정하여 getsizeof의 한계를 극복합니다.

import tracemalloc

tracemalloc.start()

# 분석하고자 하는 코드 영역
snapshot1 = tracemalloc.take_snapshot()
large_data = [i for i in range(100000)]
snapshot2 = tracemalloc.take_snapshot()

stats = snapshot2.compare_to(snapshot1, 'lineno')
for stat in stats[:3]:
    print(stat)
    

Example 7: Pandas DataFrame 전용 memory_usage 활용

데이터 분석 시 sys.getsizeof(df)는 인덱스와 컬럼 데이터 일부를 누락할 수 있습니다.

import pandas as pd

df = pd.DataFrame({'a': range(1000000), 'b': ['text'] * 1000000})
# deep=True 옵션을 주어야 실제 문자열 데이터 크기까지 계산함
print(df.memory_usage(deep=True).sum())
    

3. 전문가의 조언: 효율적인 메모리 관리를 위한 설계 방향

파이썬에서 메모리를 정확히 측정하는 것보다 더 중요한 것은 "메모리를 덜 사용하는 구조"를 설계하는 것입니다. sys.getsizeof의 결과에 일희일비하기보다, Generator를 활용한 지연 평가(Lazy Evaluation)를 도입하거나 대용량 수치 데이터는 반드시 NumPy/Pandas와 같은 C 기반 라이브러리를 사용하여 파이썬 객체 오버헤드를 줄이는 전략이 필요합니다.


4. 출처 및 참고 문헌

  • Python Software Foundation, "sys.getsizeof() documentation", docs.python.org.
  • Fluent Python (2nd Edition) by Luciano Ramalho.
  • High Performance Python by Micha Gorelick and Ian Ozsvald.
  • Pympler Project Documentation, "Tracking memory usage in Python".
728x90