-
어느날 신입 개발자가 나에게 물었다..."python에서 staticmethod를 사용하는 것에 있어서 메모리 이슈가 없는 것 일까요?" (feat. java)💻 프로그래밍/Python 2022. 7. 17. 18:57
제곧내(제목이 곧 내용)입니다! ㅋㅋㅋ 최근 저희팀에 합류하신 ㅅㄱ님께서 개발 중 이런 질문을 하셨습니다.
사실 이질문을 듣고
라는 생각이 먼저 떠올랐습니다ㅠㅠ 그리고 python을 메인으로 쓰면서 이런 기본적인 부분을 숙지하지 않았다는게 부끄럽기도 했습니다.
(함께 자료를 찾아보고 토론의 시간을 가짐)
처음 C, C++로 개발을 했을 때는 메모리에 관리에 신경 쓰면서 개발을 했던 것 같은데 python으로 개발하면서 이런 부분을 신경을 안 썼던 것 같습니다. (python은 개발자가 동적으로 메모리를 할당할 수 없고 알아서 관리해줍니다)
C++처럼 malloc(), calloc(), realloc(), free() 등을 통해 동적 할당을 제어하지도 않고, 변수에 그냥 갖다박으면(?) 알아서 메모리 할당이 되기 때문에 "아 그렇구나, 그냥 그런구나"라고 넘어갔던 것 같습니다.
그래서 이 부분을 블로그로 한 번 정리해봐야겠다 하고 글을 쓰게 되었습니다!
1. 메모리 구조
먼저 메모리의 구조에 대해서 알아보겠습니다.
메모리 구조는 위와 같습니다. 아마 한 번쯤은 다들 보셨을 것 같아요! 위 메모리 구조를 보면서 신입 개발자분의 질문을 다시 되돌아보겠습니다.
질문의 키워드는 일단 static입니다. 원래 Java를 메인 언어로 하셨던 분이라 자연스럽게 Java의 특징과 메모리를 비교할 수밖에 없었을 것 같아요! Java에서는 static으로 변수나 클래스를 선언하면 data영역에 저장되어 메모리가 낭비될 수도 있고 클래스의 staticmethod로 선언하게 되면 data영역에 저장되어 객체의 생성 주기와 상관없기 때문에 객체지향과 멀어진다고 합니다.
Okay! Java에서는 뭐 이런 이유들이 있어서 static을 난발하면 안 되는구나! 써야 할 곳에서만 써야 하는구나라고 알았습니다. 그럼 python은 어떻게 메모리를 할당할까요?
2. python memory management
python의 메모리 관리는 python의 모든 객체와 데이터 구조가 프라이빗 힙(heap)과 관련 있다.
그리고 이 프라이빗 힙 관리는Python memory manger를 통해서 내부적으로 이루어진다.요약하자면 python memory manager가 python의 모든 객체, 데이터 구조를 프라이빗 힙에 저장한다는 것 같습니다.
위 이미지를 보면 python은 stack, heap memory 두 가지를 사용합니다. stack memory에는 참조자가 저장되고 heap memory에는 객체가 저장됩니다. 기존에 C++, Java와는 다르게 메모리에 값이 들어가는 형태가 아닌 heap memory에 객체가 생성(int, string, class 등)이 되면 변수에서 그곳을 참조(reference)하는 형태로 메모리 할당이 됩니다.
python을 공부하다 보면 이런 이야기를 들어보셨을 겁니다.
python에서 모든 것은 객체(object)이다
네 맞습니다. python에서 모든것은 객체입니다. 코드로 한번 확인해보겠습니다.
isinstance함수로 object 속성을 가지고 있는지 체크하니까 클래스, 함수, 문자열, 숫자 모두 True로 나왔습니다.
3. python reference & reference counting
python에서 모든 것은 객체인 걸 확인했습니다. 이제 이 객체들을 어떻게 참조하는지 코드로 확인해보겠습니다.
첫 번째 코드를 보면 '피트 웨어 제이'라는 string 객체를 a, b가 똑같이 바라보고 있습니다. (id가 동일) 두번째 코드에서는 서로 다른 객체를 바라보고 있죠. 이걸 보고 확인 할 수 있는것은 python에서는 '피트웨어 제이'라는 string 객체를 만들고 변수가 참조(reference)하는 방식으로 memory를 할당하고 있습니다.
그리고 python garbage collector가 reference counting을 체크하여 더 이상 참조되지 않는(reference counting이 0이 될 때) 객체를 제거합니다. reference counting을 체크해보겠습니다.
코드를 보면 '피트 웨어 제이'를 참조할 때마다 reference counting이 올라가는 걸 볼 수 있습니다. 처음에 1이 아닌 이유는 getrefcount함수에서 또 객체를 참조하기 때문이라고 여기까지는 정확히 모르겠네요;; 일단 refernce counting이 올라간거만 확인!
4. 다시 질문으로 돌아오기
python에서는 classmethod or staticmethod를 사용하는 것에 있어서 메모리 이슈가 없는 것일까요?
Java에서는 static은 프로그램이 실행 시에 data영역에 생성되어서 많이 사용할 경우
메모리를 낭비하게 되는 이슈가 있습니다.이제 우리의 대답은...!
python에서는 모든 것이 객체이고 classmethod, staticmethod 상관없이
모든 객체(int, str, class 등)는 heap에 저장이 된다.
그리고 선언된 변수들은 heap에 있는 개체를 참조(reference)한다.
그렇기 때문에 data영역에 메모리가 생성되지 않는다.
그리고 객체의 reference counting이 0이 될 때
python garbage collector가 heap에서 메모리를 해제한다.라고 말할 수 있습니다! (반박 시 댓글 부탁드립니다!)
더불어 위 표를 참고하면 좀 더 도움이 될 것 같습니다.
위 내용과는 조금 별개로 python에서 classmethod와 staticmethod가 비슷하게 사용될 수 있는데 저의 경우는 staticmethod는 유틸 느낌의 method를 구현할 때 사용합니다.
그리고 python class에서 staticmethod가 일반 method보다 메모리를 더 적게 차지합니다.
추가로 효율적인 파이썬 코드 작성하는 법이 있으니 참고하시길 바랍니다!
5. 마치며
오랜만에 뭔가 좀 low level의 이야기를 다뤄봤는데 재밌었던 것 같습니다. 문서와 블로그들을 참고하면서 정리해봤는데 틀린 게 없나 걱정이 되네요ㅎㅎ 혹시나 잘못된 이야기가 있다면 댓글로 부탁드립니다!
그럼 오늘도 즐거운 코딩 하시길 바래요~
참고자료
https://docs.python.org/3/c-api/memory.html#memory-management
https://noirstar.tistory.com/10
https://woochan-autobiography.tistory.com/867
https://meoru-tech.tistory.com/25
https://hkim-data.tistory.com/184
'💻 프로그래밍 > Python' 카테고리의 다른 글
RabbitMQ 톺아보기 2부 (feat.pika) (0) 2022.09.17 RabbitMQ 톺아보기 1부 (0) 2022.09.12 Context Manager 섹시하게 사용하기 😎 (0) 2022.01.22 Python 에서 몽고반점 말고 몽고디비(MongoDB) 다뤄보기 (0) 2021.09.26 비동기로 Third-party API 처리하기 (feat. aiohttp, asyncio) (0) 2021.04.07