ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • cPython [Deep Dive to Object] - 1
    Python 2021. 4. 21. 23:31

    python에서 Cyclic GC가 어떻게 작동하지 알아보기 위해서 cpython repository를 fork해 놓았었다.

    그 당시 깊이 이해하지 못해 별다른 소득이 없었는데(변명이지만, 프로젝트 때문에 정말 바빴다...), 이번 기회에 python에서 object가 무었인지 부터 시작해 깊게 알아볼 계획이다.

     

    python에서 object가 도대체 뭔지! 어떻게 관리되는지! 알아보자.

     

     

    발단

    '파이썬의 배열에 끊임없이 원소를 추가하면 어떻게될까?'라는 생각을 하다가 이 고민을 하기 시작하게 되었다.

    처음 머릿속에 든 생각은 파이썬은 객체의 Virtual Memory Address를 id로 사용하고, 배열이 저장될 메모리를 재할당하면 id도 바뀌겠지? 라는 생각이었다.

    그래서 아래와 같은 간단하고, 귀여운 코드를 짜서 실행시켜 보았다.

    arr = []
    prev_id = id(arr)
    i = 1
    print('prev_id:',prev_id)
    while prev_id == id(arr):
        arr.append(i)
        if(i % 1000 == 0):
            print(i)
        i += 1
    
    print(id(arr))

    local에서 실행시켰다가 컴퓨터가 버티지 못하는 것을 보고 colab으로 옮겨 실험을 진행했다...

     

    결과는 while문이 종료되지 않았고, 이유는 아래와 같다.

    id
    Return the “identity” of an object. This is an integer which is guaranteed to be unique and constant for this object during its lifetime. Two objects with non-overlapping lifetimes may have the same id() value.
    ref

     

    그래서 고민 끝에 append하는데 걸리는 시간을 측정해보기로 했다! 근본적으로 궁금했던 점은 array에 값들을 append할 메모리 공간이 부족(할당받은 메모리를 모두 소진했을 때)할 때 어떤 일이 일어나는지 였다. 내 예상으로는 당연히 reallocate될 것이라 생각했고 이를 확인하고 싶었다.

    reallocate되는지를 확인해보고 싶었고, append 하는데 걸리는 시간이 길다면 reallocate되었기 때문이 아닐까 라는 생각을 하게 되었다.

    시간을 측정했고, 너무 짧아서 10,000,000회 append당 걸리는 시간을 측정하는 코드를 작성했다.

    ps. append하는값을 3으로 일정하게 변경했다. 1씩 증가하는 i를 append하게 된다면, intending될 수 없고, i자체도 계속 숫자를 메모리에 할당해주어야 하기 때문에 side effect가 생길까 염려되었다. 파이썬에서 기본적으로 메모리에 할당되어 있는 -5 ~ 256사이의 숫자중 3을 고른 것이다.

     

    arr = [3]
    prev_id = id(arr[0])
    print('arr_id:',hex(id(arr)))
    print('prev_id:',hex(prev_id))
    i = 1
    import time
    start = time.time()
    while prev_id == id(arr[0]):
        arr.append(3)
        if(i % 10000000 == 0):
            tmp = time.time()
            print(hex(id(arr[-1])), i, tmp-start)
            start = tmp
        i += 1
    
    print(id(arr))

    결과로 얻은 값들을 그래프로 나타내 보았다.

     

    x: append(10,000,000회), y: time(s)

    세로축은 3을 array에 10,000,000회 append하는데 걸린 시간, 가로축은 총 append한 횟수를 나타낸다.

    주기적으로 뾰족하게 솟아오른 지점이 나타난다는 것을 알 수 있다.

     

    colab의 log를 캡쳐해온 것인데, large alloc warning이 발생한다. 솟아오른 지점에서 배열을 realloc하는구나 라고 추측된다. 캐시의 영향도 존재할 듯 하다. (현재는 추측이며, 정확한 원인을 알아가는 과정이다. 이 과정을 포스팅할 계획이다.)

     

     

    물론, 메모리는 무한하지 않기 때문에 while문은 아래의 에러를 띄우며 종료되었다.

    exception MemoryError
    Raised when an operation runs out of memory but the situation may still be rescued (by deleting some objects). The associated value is a string indicating what kind of (internal) operation ran out of memory. Note that because of the underlying memory management architecture (C’s malloc() function), the interpreter may not always be able to completely recover from this situation; it nevertheless raises an exception so that a stack traceback can be printed, in case a run-away program was the cause.

     

     

    현재 이와 관련해 cPython의 PyByteArrayObject가 어떻게 구성되어있고, append될때 어떻게 동작하는지 살펴보고 있다. 

    추가로, stackOverFlow에서도 토론을 진행중이다. (혹시나 이 글을 보신다면 많은 참여 부탁드립니다!)

    stackoverflow.com/questions/67200979/what-happened-when-python-reallocate-object-and-how-can-i-notice-it?noredirect=1#comment118810216_67200979

     

    What happened when python reallocate object and how can I notice it?

    Thank you for visiting. At first, I was curious about what happened when append object to array infinitely. So, I tried. append 3 to array until id of array changed My idea is like below. Someday,

    stackoverflow.com

     

    reference 

    - docs.python.org/3/library/exceptions.html#exceptions.MemoryError

    - docs.python.org/3/library/functions.html#id

    'Python' 카테고리의 다른 글

    Python - Variable Scope  (0) 2021.01.06
    Python - Call by Object Reference  (1) 2020.12.26
    Python - 함수에 배열을 인자로 전달할 때  (0) 2020.12.23
    Python?  (0) 2020.12.21
Designed by Tistory.