튜플이 목록보다 메모리 공간을 적게 차지하는 이유는 무엇입니까?
A tuplePython의 메모리 공간이 줄어듭니다.
>>> a = (1,2,3)
>>> a.__sizeof__()
48
반면에.list메모리 공간을 더 많이 사용합니다.
>>> b = [1,2,3]
>>> b.__sizeof__()
64
Python 메모리 관리에서 내부적으로 어떤 일이 발생합니까?
Cpython을 사용하고 있으며 64비트를 사용하고 있다고 가정합니다(Cpython 2.7 64비트에서도 동일한 결과가 나타남).다른 파이썬 구현이나 32비트 파이썬이 있다면 차이가 있을 수 있습니다.
실시여부와 관계없이,lists는 가변 크기인 동안tuples는 크기가 고정되어 있습니다.
그렇게tuples는 구조물 내부에 요소를 직접 저장하고, 반면에 목록은 간접 레이어(요소에 대한 포인터를 저장함)가 필요합니다.이 간접 계층은 64비트 시스템의 포인터로, 64비트이므로 8바이트입니다.
하지만 또 하나는list너무 많이 할당합니다.그렇지않으면list.append가 될 것입니다O(n)operation always - 상각을 설정합니다.O(1)(much 더 빨리!!!)그것이 allocates을 넘었습니다.하지만 이제는 할당된 크기와 채워진 크기를 추적해야 합니다 (tuple할당된 크기와 채워진 크기가 항상 동일하기 때문에 하나의 크기만 저장하면 됩니다.이는 각 목록이 64비트 시스템에서 64비트 정수인 또 다른 "크기"를 저장해야 한다는 것을 의미하며, 다시 8바이트입니다.
그렇게lists는 적어도 16바이트 이상의 메모리가 필요합니다.tuple가 왜 "라고 했지요 내가 왜 "적어도"라고 했지요?너무 많은 할당 때문에.과잉 할당은 필요한 공간보다 더 많은 공간을 할당한다는 것을 의미합니다.그러나 초과 할당의 양은 목록을 만드는 "방법"과 추가/삭제 기록에 따라 달라집니다.
>>> l = [1,2,3]
>>> l.__sizeof__()
64
>>> l.append(4) # triggers re-allocation (with over-allocation), because the original list is full
>>> l.__sizeof__()
96
>>> l = []
>>> l.__sizeof__()
40
>>> l.append(1) # re-allocation with over-allocation
>>> l.__sizeof__()
72
>>> l.append(2) # no re-alloc
>>> l.append(3) # no re-alloc
>>> l.__sizeof__()
72
>>> l.append(4) # still has room, so no over-allocation needed (yet)
>>> l.__sizeof__()
72
이미지들
위의 설명에 곁들일 이미지를 만들기로 했습니다.어쩌면 이것들이 도움이 될지도 모릅니다.
예제에서 메모리에 저장된 방법은 이와 같습니다.빨간색(자유형) 사이클과의 차이점을 강조했습니다.
그것은 사실 대략적인 것일 뿐입니다.int개체도 파이썬 개체이고 CPython은 작은 정수를 재사용하기 때문에 메모리에 있는 개체에 대한 더 정확한 표현은 다음과 같습니다.
유용한 링크:
:__sizeof__"정확한" 사이즈는 돌려주지 않습니다!저장된 값의 크기만 반환합니다.그러나 사용 시 결과는 다릅니다.
>>> import sys
>>> l = [1,2,3]
>>> t = (1, 2, 3)
>>> sys.getsizeof(l)
88
>>> sys.getsizeof(t)
72
추가 바이트는 24개입니다.이것들은 진짜입니다. 그것은 쓰레기 수집기 오버헤드입니다.__sizeof__방법.일반적으로 마법 방법을 직접 사용해서는 안 되기 때문입니다. 이 경우 마법 방법을 처리하는 방법을 알고 있는 함수를 사용합니다. (실제로 GC 오버헤드를 반환된 값에 추가합니다.)__sizeof__).
CPython 코드베이스에 대해 좀 더 자세히 알아보도록 하겠습니다. 실제로 크기가 어떻게 계산되는지 확인할 수 있도록 말이죠.구체적인 예를 들어보면 초과 할당이 수행되지 않았으므로 이에 대해서는 언급하지 않겠습니다.
여기서는 64비트 값을 사용하겠습니다.
입니다.lists는 다음 함수로부터 계산됩니다.
static PyObject *
list_sizeof(PyListObject *self)
{
Py_ssize_t res;
res = _PyObject_SIZE(Py_TYPE(self)) + self->allocated * sizeof(void*);
return PyInt_FromSsize_t(res);
}
여기 매크로가 있습니다.ob_typeself()PyList_Type) 동안에_PyObject_SIZE는 해당 유형에서 캡처하는 또 다른 매크로입니다.tp_basicsize다음과 같이 계산됩니다.sizeof(PyListObject)어디에PyListObject인스턴스 구조입니다.
구조물에는 세 개의 필드가 있습니다.
PyObject_VAR_HEAD # 24 bytes
PyObject **ob_item; # 8 bytes
Py_ssize_t allocated; # 8 bytes
해당 내용을 설명하는 주석이 있습니다. 위 링크를 따라 읽어 보십시오.PyObject_VAR_HEAD 3개의 8바이트 필드로 확장(ob_refcount,ob_type그리고.ob_size) 그래서24바이트 기여
그래서 지금은res다음과 같습니다.
sizeof(PyListObject) + self->allocated * sizeof(void*)
또는:
40 + self->allocated * sizeof(void*)
목록 인스턴스에 할당된 요소가 있는 경우.두번째 파트는 그들의 기여도를 계산합니다.self->allocated, 이름에서 알 수 있듯이 할당된 요소의 수를 유지합니다.
요소가 없는 경우 목록 크기는 다음과 같이 계산됩니다.
>>> [].__sizeof__()
40
즉, 인스턴스 구조물의 크기.
tuple객체는 a를 정의하지 않습니다.tuple_sizeof기능.대신 크기를 계산하는 데 사용됩니다.
static PyObject *
object_sizeof(PyObject *self, PyObject *args)
{
Py_ssize_t res, isize;
res = 0;
isize = self->ob_type->tp_itemsize;
if (isize > 0)
res = Py_SIZE(self) * isize;
res += self->ob_type->tp_basicsize;
return PyInt_FromSsize_t(res);
}
에는.list s, .tp_basicsize그리고, 만약 물체가 0이 아닌 것을tp_itemsize(즉, 가변 길이 인스턴스를 갖는다는 뜻), 튜플의 항목 수를 곱합니다.tp_itemsize.
tp_basicsize다시 쓰임sizeof(PyTupleObject)여기서 구조물은 다음을 포함합니다.
PyObject_VAR_HEAD # 24 bytes
PyObject *ob_item[1]; # 8 bytes
그래서, 어떤 요소도 없이 (즉,Py_SIZE돌아온다0) 빈 튜플의 크기는 다음과 같습니다.sizeof(PyTupleObject):
>>> ().__sizeof__()
24
어? 여기 이상한 점이 있어요 설명을 못 찾았는데요tp_basicsizetuples는 실제로 다음과 같이 계산됩니다.
sizeof(PyTupleObject) - sizeof(PyObject *)
왜 추가로8바이트가 제거됨tp_basicsize제가 미처 알아내지 못한 부분입니다. (가능한 설명은 MSeifert의 코멘트 참조)
그러나 이것은 기본적으로 당신의 구체적인 예에서 다른 점입니다.lists는 또한 다시 초과 allocate을 해야 할 시기를 결정하는 데 도움이 되는 할당된 요소의 수를 유지합니다.
이제 추가 요소가 추가되면 O(1) 추가를 달성하기 위해 목록이 실제로 이 오버 할당을 수행합니다.이렇게 하면 MSeifert가 답변에서 잘 커버하기 때문에 크기가 더 커집니다.
MS Seifert 답변은 이를 폭넓게 다루고 있습니다. 간단히 설명하자면 다음을 생각해 볼 수 있습니다.
tuple 불변입니다.한 번 설정하면 변경할 수 없습니다.따라서 해당 개체에 할당해야 하는 메모리 양을 미리 알 수 있습니다.
list 변형 가능합니다.항목을 추가하거나 삭제할 수 있습니다.그것은 현재 크기를 알아야 합니다.필요에 따라 크기가 조정됩니다.
무료 식사는 없습니다. 이러한 기능에는 비용이 수반됩니다.따라서 목록에 대한 메모리의 오버헤드.
튜플의 크기는 접두사로 붙습니다. 즉, 튜플 초기화 시 인터프리터가 포함된 데이터에 대한 공간을 충분히 할당하므로 이는 변경할 수 없습니다(수정할 수 없습니다.목록은 가변 개체이므로 동적 메모리 할당을 의미하는 반면, 목록을 추가하거나 수정할 때마다 공간을 할당하지 않기 위해(변경된 데이터를 포함하고 데이터를 복사할 수 있는 공간을 할당) 추가 및 수정과 같은 향후 런타임 변경을 위한 공간을 할당합니다.
그 정도면 충분히 요약이 됩니다.
언급URL : https://stackoverflow.com/questions/46664007/why-do-tuples-take-less-space-in-memory-than-lists
'codememo' 카테고리의 다른 글
| html 하이퍼링크 'a' 태그의 기본 링크 색상을 제거하려면 어떻게 해야 합니까? (0) | 2023.10.30 |
|---|---|
| AJAX 성공 후 모드 창을 닫으려면 어떻게 해야 합니까? (0) | 2023.10.30 |
| 데이터 프레임을 여러 데이터 프레임으로 분할 (0) | 2023.10.30 |
| Angular JS - 단추 클릭 시 지시문에서 템플릿 html 로드 (0) | 2023.10.30 |
| JavaScript에서 MariaDB로 데이터 전송 시 밀리초의 정확도 유지 (0) | 2023.10.30 |

