Python는 개발 편의성을 위해서 메모리 관리를 별도로 하지 않아도 사용이 가능한 프로그램 언어이다.
그리고 최근에 나오는 언어들은 GC(Garbage Collection)라고 하는 메모리 청소 도구 통해 자동으로 메모리에서 불필요한 데이터를 청소해 준다.
하지만 개발자라면 서비스를 위해 개발을 진행하게 되고, 이는 운영체제에서 장시간 사용되는 프로그램을 작성해야 한다는 의미이다. 이때 메모리 관리를 잘못한다면 안정성에 큰 문제가 생기게 된다. 즉 큰 장애를 만날 수 있다는 의미이다.
여기에서는 메모리 관리가 어떻게 되는지 이해하여, Python 코드를 보다 효과적으로 사용할 수 있을 것이라는 생각에, 관련 자료를 찾아서 정리해본다.
Python에서 메모리 관리에 사용하는 방식은 Reference counting(참조 횟수)를 통해서 참조가 일어나지 않는 경우 메모리 삭제하게 되는데, 가장 핵심 적인 부분은 아래와 같다.
1. Python GC는 데이터의 참조자가 0인지 확인후 메모리 할당 해제
2. 리턴시 외부 참조자가 없다면 메모리 할당 해제
대표적으로 Python에서 메모리를 할당하는 것은 바로 변수나 Class, 그리고 클래스 내에 선언한 self가 대표적으로 어떻게 메모리에서 삭제되는지 가장 기본적인 코드부터 확인해보자.
>>> def sum(y):
... x = 5
... return x + y
...
>>> a = 5
>>> b = sum(a)
>>> x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined
Python은 프로그램을 실핼할 때
위에서 아래로, 들어쓰기가 없는 코드부터 실행하고 __main__ 매직 메소드를 만나면 해당 코드를 실행하게 된다.
코드
a = 5 ## a = 5 참조자 a
b = sum(a) ##a = 5 참조자 a, y
sum 함수 실행
x = 5 ## a = 5 참조자 a, y | x = 5 참조자 x
return x + y ## a = 5 참조자 a, y | x = 5 참조자 x
b = 로 x + y 리턴 ##a = 5 참조자 a | x = 5 참조자 없음, 메모리 할당 해제 진행
b = 함수 실행 ##a = 5 참조자 a | b = 10 참조자 b
x ##메모리에서 해제되었기 때문에 오류 발생
>>> import weakref
>>> class abc():
... def __init__(self, c):
... self.data = c
>>> a = abc(1)
>>> b = a
>>> r1 = weakref.ref(a)
>>> r2 = weakref.ref(b)
>>>
>>> import weakref
>>>
>>> class abc():
... def __init__(self, d):
... self.data = d
...
>>>
>>> a = abc(1)
>>> b = a
>>> r1 = weakref.ref(a)
>>> r2 = weakref.ref(b)
>>> print('memory ref', r1)
memory ref <weakref at 0x0000026AE718FA60; to 'abc' at 0x0000026AE714A1D0>
>>> print('memory ref', r2)
memory ref <weakref at 0x0000026AE718FA60; to 'abc' at 0x0000026AE714A1D0>
Reference counting(참조 횟수) 제거
>>> b = None
>>> print('memory ref', r2)
memory ref <weakref at 0x000001904F24E3E0; to 'abc' at 0x000001904F1C4A30>
하지만 아직 a 참조자가 있기 때문에 메모리상 이상이 없는 것을 알 수 있다.
>>> a = None
>>> print('memory ref', r2)
memory ref <weakref at 0x000001904F24E3E0; dead>
이번에는 특정 함수 안에서 메모리 관리가 어떻게 이루어 지는지를 확인하기 위해서 함수 안에서 Class를 생성해보도록 하자.
>>> import weakref
>>>
>>> class abc():
... def __init__(self, c):
... self.data = c
...
>>>
>>> def sum():
... a = abc(1)
... global r1
... r1 = weakref.ref(a)
... print('memory ref', r1)
...
>>>
>>> r1 = None
>>>
>>> sum()
memory ref <weakref at 0x000001904F24E3E0; to 'abc' at 0x000001904F254A60>
>>> print('memory ref', r1)
memory ref <weakref at 0x000001904F24E3E0; dead>
'Python' 카테고리의 다른 글
Python - -u PYTHONUNBUFFERED 사용 (0) | 2024.03.25 |
---|---|
Python - Mocking/단위 테스트(Unit Test) 과 Django 활용 (0) | 2024.03.25 |
Python - List 에서 문자열 포함 유무를 확인 (0) | 2024.03.25 |
Python - sys.exit(0) 과 sys.exit(1)의 차이 exit code (0) | 2024.03.25 |
Python - Zombie Process 처리 timeout (0) | 2024.03.25 |