Python 목록 대상 실현 원리 상세 설명

Python 의 목록 은 PyListObject 를 기반 으로 이 루어 집 니 다.목록 은 요소 의 삽입,삭제,업데이트 작업 을 지원 합 니 다.따라서 PyListObject 는 길 어 지 는 대상(목록 의 길 이 는 요소 의 증가 와 삭제 에 따라 길 어 지고 짧 아 집 니 다)이자 가 변 대상(목록 의 요 소 는 목록 의 조작 에 따라 변화 하고 메모리 크기 의 동태 적 변화)입 니 다.PyListObject 의 정의:

typedef struct {
#         
int ob_refcnt; 
#        
struct _typeobject *ob_type;
#        
int ob_size; /* Number of items in variable part */
#              ,list[0]    ob_item[0]
PyObject **ob_item;
#             
Py_ssize_t allocated;
} PyListObject;
어떻게 보면 PyListObject 대상 의 정 의 는 매우 간단 합 니 다.통용 대상 을 제외 하고 모두 있 는 인용 계수(obrefcnt),유형 정보(obtype),그리고 길 어 지 는 대상 의 길이(obsize)외 에 남 은 것 은 obitem,allocated,obitem 은 목록 요소 용 기 를 진정 으로 저장 하 는 지침 입 니 다.목록 요 소 를 저장 하 는 메모리 가 있 습 니 다.이 메모리 의 크기 는 allocated 가 수용 할 수 있 는 공간 입 니 다.allocated 는 목록 에 수용 할 수 있 는 요소 크기 이 며 조건 을 만족 시 킵 니 다.
  • 0 <= ob_size <= allocated
  • len(list) == ob_size
  • ob_item==NULL 시 obsize == allocated == 0

  • 목록 개체 생 성
    PylistObject 대상 은 함수 로 PyListNew 생 성,수신 매개 변수 size,이 매개 변 수 는 목록 대상 이 수용 할 수 있 는 최대 요소 개 수 를 지정 하 는 데 사 용 됩 니 다.
    
    //      , PyList_MAXFREELIST 80
    static PyListObject *free_list[PyList_MAXFREELIST];
    //       
    static int numfree = 0;
    PyObject *PyList_New(Py_ssize_t size)
    {
    PyListObject *op; //    
    size_t nbytes; //               
    if (size < 0) {
    PyErr_BadInternalCall();
    return NULL;
    }
    /* Check for overflow without an actual overflow,
    * which can cause compiler to optimise out */
    if ((size_t)size > PY_SIZE_MAX / sizeof(PyObject *))
    return PyErr_NoMemory();
    nbytes = size * sizeof(PyObject *);
    if (numfree) {
    numfree--;
    op = free_list[numfree];
    _Py_NewReference((PyObject *)op);
    } else {
    op = PyObject_GC_New(PyListObject, &PyList_Type);
    if (op == NULL)
    return NULL;
    }
    if (size <= 0)
    op->ob_item = NULL;
    else {
    op->ob_item = (PyObject **) PyMem_MALLOC(nbytes);
    if (op->ob_item == NULL) {
    Py_DECREF(op);
    return PyErr_NoMemory();
    }
    memset(op->ob_item, 0, nbytes);
    }
    #   ob_size
    Py_SIZE(op) = size;
    op->allocated = size;
    _PyObject_GC_TRACK(op);
    return (PyObject *) op;
    }
    생 성 과정 은 다음 과 같 습 니 다:
  • size 파라미터 가 유효한 지 확인 하고 0 보다 작 으 면 NULL 로 되 돌아 갑 니 다.생 성 실패
  • size 인자 가 Python 이 받 아들 일 수 있 는 크기 를 초과 하 는 지 확인 합 니 다.PY 보다 크 면SIZE_MAX(64 비트 기기 8 바이트,32 비트 기기 4 바이트)메모리 가 넘 칩 니 다.
  • 버퍼 검사 freelist 에 사용 가능 한 대상 이 있 는 지,있 으 면 버퍼 에서 직접 사용 하고,없 으 면 새 PyListObject 를 만 들 고 메모 리 를 분배 합 니 다.
  • ob 초기 화item 에 있 는 원소 의 값 은 Null
  • 입 니 다.
  • PyListObject 의 allocated 와 ob 설정size。
  • PYLISTOBJECT 대상 버퍼
    free_list 는 PyListObject 대상 의 버퍼 입 니 다.크기 는 80 입 니 다.그러면 PyListObject 대상 은 언제 버퍼 에 가입 합 니까 free리스트 는 요?정 답 은 listdealloc 방법 중:
    
    static void
    list_dealloc(PyListObject *op)
    {
    Py_ssize_t i;
    PyObject_GC_UnTrack(op);
    Py_TRASHCAN_SAFE_BEGIN(op)
    if (
    i = Py_SIZE(op);
    while (--i >= 0) {
    Py_XDECREF(op->ob_item[i]);
    }
    PyMem_FREE(op->ob_item);
    }
    if (numfree < PyList_MAXFREELIST && PyList_CheckExact(op))
    free_list[numfree++] = op;
    else
    Py_TYPE(op)->tp_free((PyObject *)op);
    Py_TRASHCAN_SAFE_END(op)
    }
    PyListObject 대상 이 소각 되 었 을 때 목록 에 있 는 모든 요소 의 인용 수 를 1 로 줄 인 다음 ob 를 방출 합 니 다.item 이 사용 하 는 메모리 입 니 다.버퍼 공간 이 채 워 지지 않 았 다 면 이 PyListObject 를 버퍼 에 추가 하 십시오.(이때 PyListObject 가 사용 하 는 메모리 가 시스템 에 진정 으로 회수 되 지 않 습 니 다.다음 에 PyListObject 를 만 들 려 면 버퍼 에서 PyListObject 를 우선 가 져 옵 니 다.)그렇지 않 으 면 PyListObject 대상 의 메모리 공간 을 풀 어 줍 니 다.
    목록 요소 삽입
    목록 의 특정한 위치의 값 을 설정 할 때"list[1]=0"과 같이 목록 의 메모리 구 조 는 변 하지 않 고 목록 에 요 소 를 삽입 할 때 목록 의 메모리 구 조 를 바 꿉 니 다.
    
    static int
    ins1(PyListObject *self, Py_ssize_t where, PyObject *v)
    {
    // n       
    Py_ssize_t i, n = Py_SIZE(self);
    PyObject **items;
    if (v == NULL) {
    PyErr_BadInternalCall();
    return -1;
    }
    if (n == PY_SSIZE_T_MAX) {
    PyErr_SetString(PyExc_OverflowError,
    "cannot add more objects to list");
    return -1;
    }
    if (list_resize(self, n+1) == -1)
    return -1;
    if (where < 0) {
    where += n;
    if (where < 0)
    where = 0;
    }
    if (where > n)
    where = n;
    items = self->ob_item;
    for (i = n; --i >= where; )
    items[i+1] = items[i];
    Py_INCREF(v);
    items[where] = v;
    return 0;
    }
    목록 위 치 를 설정 하 는 값 보다 삽입 작업 이 PyListObject 용량 크기 를 한 번 더 조정 해 야 합 니 다.논 리 는 list 입 니 다.resize,그 다음은 where 이후 의 요소 위 치 를 옮 기 는 것 입 니 다.
    
    // newsize:       
    static int 
    list_resize(PyListObject *self, Py_ssize_t newsize)
    {
    PyObject **items;
    size_t new_allocated;
    Py_ssize_t allocated = self->allocated;
    if (allocated >= newsize && newsize >= (allocated >> 1)) {
    assert(self->ob_item != NULL || newsize == 0);
    Py_SIZE(self) = newsize;
    return 0;
    }
    new_allocated = (newsize >> 3) + (newsize < 9 ? 3 : 6);
    /* check for integer overflow */
    if (new_allocated > PY_SIZE_MAX - newsize) {
    PyErr_NoMemory();
    return -1;
    } else {
    new_allocated += newsize;
    }
    if (newsize == 0)
    new_allocated = 0;
    items = self->ob_item;
    if (new_allocated <= (PY_SIZE_MAX / sizeof(PyObject *)))
    PyMem_RESIZE(items, PyObject *, new_allocated);
    else
    items = NULL;
    if (items == NULL) {
    PyErr_NoMemory();
    return -1;
    }
    self->ob_item = items;
    Py_SIZE(self) = newsize;
    self->allocated = new_allocated;
    return 0;
    }
    allocated>=newsize&&newsize>=(allocated/2)을 만족 시 킬 때 list 의 요소 길 이 를 간단하게 바 꾸 면 PyListObject 대상 은 메모리 공간 을 재배 치 하지 않 고 메모리 공간 을 재배 치 합 니 다.만약 newsizeallocated 가 되면 메모리 공간 을 확대 합 니 다.뉴스 id==0 시 메모리 공간 이 0 으로 줄 어 듭 니 다.

    총결산
  • PyListObject 버퍼 의 생 성 은 목록 이 삭 제 될 때 발생 합 니 다.
  • PyListObject 대상 의 생 성 은 두 단계 로 나 뉜 다.먼저 PyListObject 대상 을 만 든 다음 에 요소 목록 을 NULL 로 초기 화 합 니 다.
  • PyListObject 대상 의 소각 은 두 단계 로 나 뉜 다.먼저 PyListObject 대상 의 요소 목록 을 없 애고 PyListObject 자 체 를 없앤다.
  • PyListObject 대상 메모리 의 점용 공간 은 목록 길이 의 변화 에 따라 조 정 됩 니 다.
  • 이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

    좋은 웹페이지 즐겨찾기