programing

Python에서 메모리 해제

mytipbox 2023. 6. 7. 23:52
반응형

Python에서 메모리 해제

다음 예제의 메모리 사용과 관련하여 몇 가지 관련 질문이 있습니다.

  1. 내가 통역을 맡으면,

    foo = ['bar' for _ in xrange(10000000)]
    

    ▁to까지 올라갑니다.80.9mb그러면 저는.

    del foo
    

    실제 기억은 내려가지만, 오직.30.4mb는 통사는다사니다합용음을을 합니다.4.4mb기준선 그래서 릴리스하지 않는 것의 이점은 무엇입니까?26mbOS에 대한 메모리?Python이 그 많은 메모리를 다시 사용할 수 있다고 생각하면서 "미리 계획"하고 있기 때문입니까?

  2. 은 출시는이유되이▁why50.5mb특히 - 방출되는 양은 무엇을 기준으로 합니까?

  3. Python이 사용된 모든 메모리를 강제로 해제할 수 있는 방법이 있습니까(만약 당신이 다시 그렇게 많은 메모리를 사용하지 않을 것이라는 것을 안다면)?

참고 이 질문은 Python에서 메모리를 어떻게 명시적으로 확보할 수 있습니까?와 다릅니다. 왜냐하면 이 질문은 인터프리터가 가비지 컬렉션을 통해 개체를 해제한 후에도 기본값에서 메모리 사용량의 증가를 주로 다루기 때문입니다.gc.collect또는 그렇지 않음).

여기서 당신이 정말로 신경쓰는 질문은 다음과 같습니다.

Python이 사용된 모든 메모리를 강제로 해제할 수 있는 방법이 있습니까(만약 당신이 다시 그렇게 많은 메모리를 사용하지 않을 것이라는 것을 안다면)?

아니요, 없습니다.하지만 쉬운 해결책이 있습니다. 바로 자녀 프로세스입니다.

5분 동안 500MB의 임시 스토리지가 필요하지만 그 후 2시간 동안 더 실행해야 하고 다시는 그렇게 많은 메모리를 사용하지 않을 경우 하위 프로세스를 생성하여 메모리 집약적인 작업을 수행합니다.자식 프로세스가 사라지면 메모리가 해제됩니다.

이것은 완전히 사소하고 무료인 것은 아니지만, 꽤 쉽고 저렴하며, 보통 거래가 가치가 있을 만큼 충분히 좋습니다.

첫째, 하위 프로세스를 만드는 가장 쉬운 방법은 다음과 같습니다(또는 3.1 이전 버전의 경우 PyPI의 백포트).

with concurrent.futures.ProcessPoolExecutor(max_workers=1) as executor:
    result = executor.submit(func, *args, **kwargs).result()

조금 더 제어가 필요한 경우 모듈을 사용합니다.

비용은 다음과 같습니다.

  • 일부 플랫폼, 특히 Windows에서는 프로세스 시작이 다소 느립니다.여기서 우리는 분 단위가 아니라 몇 밀리초 단위로 이야기하고 있습니다. 만약 여러분이 300초의 가치가 있는 일을 하기 위해 한 아이를 회전시키고 있다면, 여러분은 그것을 알아차리지도 못할 것입니다.하지만 무료는 아닙니다.
  • 사용하는 임시 메모리의 양이 많은 경우 이 작업을 수행하면 기본 프로그램이 스왑 아웃될 수 있습니다.물론 장기적으로는 시간을 절약할 수 있습니다. 메모리가 영원히 남아 있다면 언젠가는 스왑으로 이어져야 하기 때문입니다.그러나 이는 일부 사용 사례에서 점진적인 속도 저하를 매우 눈에 띄는 동시(초기) 지연으로 바꿀 수 있습니다.
  • 프로세스 간에 대량의 데이터를 보내는 속도가 느릴 수 있습니다.를 보내고 결과를 것에 입니다. 받는 다말드리지만씀상의, 2K이수를인의것내에는시보이대받보데대해못고말알만지경겠하도지리차아이는에우터의량는시씀를하는고내를받과결반환상▁(k▁again▁mechanisma▁2▁some,▁if▁and,k▁you▁other▁to▁wantk못대▁you,▁file▁use'k알데▁youll,만,▁getting보▁64mmap그 의 경우; 기타는또메리모페드의 공유 ; 의공유메▁api APImultiprocessing등).
  • 를 전송하는 수 있어야 을 의미합니다(공유 에는 프세스또데대전는다것은한데송를이이것다한우경을의니합다는는미저하메장수에로있터야어할리클모공또유파는는일링를피터량에의간또▁sending▁have▁the▁means,▁large▁betweenor우경le▁((▁processes▁pick▁data▁be▁to다▁you,)).struct-가능하거나 이상적인ctypes -가능).

힙에 할당된 메모리는 상한 표시를 받을 수 있습니다.개체를 Python의 최적화로 복잡합니다(Python의 내부 최적화).PyObject_Malloc)는)로 풀에서 사용됩니다.수영장 자체가 256KiB 아레나에 있기 때문에 한 풀에 한 블록만 사용하면 256KiB 아레나 전체가 해제되지 않습니다.파이썬 3.3에서는 작은 개체 할당자가 힙 대신 익명 메모리 맵을 사용하는 것으로 전환되었으므로 메모리를 해제하는 데 더 나은 성능을 발휘해야 합니다.

또한 기본 제공 유형은 작은 개체 할당자를 사용할 수도 있고 사용하지 않을 수도 있는 이전에 할당된 개체의 자유 목록을 유지 관리합니다.int로 프리리스트를 하며, 하려면 은자할메당프유를트며지하유리스리삭, 필호다니요합출이면려형제하체로리모된▁calling▁type▁withist를 호출해야 합니다.PyInt_ClearFreeList()전체를 수행하여 간접적으로 호출할 수 있습니다.gc.collect.

이렇게 해보시고, 뭐가 있는지 말씀해주세요.여기 psutil에 대한 링크가 있습니다.프로세스.memory_info.

import os
import gc
import psutil

proc = psutil.Process(os.getpid())
gc.collect()
mem0 = proc.memory_info().rss

# create approx. 10**7 int objects and pointers
foo = ['abc' for x in range(10**7)]
mem1 = proc.memory_info().rss

# unreference, including x == 9999999
del foo, x
mem2 = proc.memory_info().rss

# collect() calls PyInt_ClearFreeList()
# or use ctypes: pythonapi.PyInt_ClearFreeList()
gc.collect()
mem3 = proc.memory_info().rss

pd = lambda x2, x1: 100.0 * (x2 - x1) / mem0
print "Allocation: %0.2f%%" % pd(mem1, mem0)
print "Unreference: %0.2f%%" % pd(mem2, mem1)
print "Collect: %0.2f%%" % pd(mem3, mem2)
print "Overall: %0.2f%%" % pd(mem3, mem0)

출력:

Allocation: 3034.36%
Unreference: -752.39%
Collect: -2279.74%
Overall: 2.23%

편집:

시스템 내 다른 프로세스의 영향을 제거하기 위해 프로세스 VM 크기와 관련된 측정으로 전환했습니다.

C 런타임(예: glibc, msvcrt)은 맨 위의 연속적인 사용 가능 공간이 일정하거나 동적이거나 구성 가능한 임계값에 도달하면 힙을 축소합니다.glibc를 사용하면 (M_TRIM_THRESHOLD)로 이를 조정할 수 있습니다.이러한 점을 고려할 때, 힙이 블록보다 더 많이, 심지어 훨씬 더 많이 줄어든다고 해도 놀라운 일은 아닙니다.free.

3.x에서range 개의 목록이 int물건들.설사 그렇다 하더라도,int의 type은 으로 2 3.x 파일 의 2.x 파일 입니다.long프리리스트를 구현하지 않는 것입니다.

Eryksun은 1번 질문에 답했고, 저는 3번 질문(원래 4번)에 답했지만, 이제 2번 질문에 답하겠습니다.

특히 50.5mb를 출시하는 이유는 무엇입니까? - 출시되는 양은 얼마입니까?

그것이 기반으로 하는 것은 궁극적으로 파이썬 내부의 일련의 우연과malloc그것은 예측하기 매우 어렵습니다.

첫째, 메모리를 측정하는 방법에 따라 실제로 메모리에 매핑된 페이지만 측정할 수 있습니다.이 경우 호출기에 의해 페이지가 전환될 때마다 메모리가 해제되지 않은 경우에도 "해제됨"으로 표시됩니다.

사용 중인를 측정하고 수도 와 같이 ) 되었지만 태그가 지정된 도 있습니다. 또 는 사 를 할 중 터 와 않 페 이 었 지 되 같 은 당 이 이지있수시태게당우할된 (Linux 낙 관 적 스 계 템 의 산 으 하 도 로 경 할 지 만 과 가 그 만 는 용 지 치MADV_FREE 타기.

할당된 페이지를 실제로 측정하는 경우(실제로는 그다지 유용한 작업은 아니지만 요청하는 내용인 것 같습니다) 페이지가 실제로 할당 해제된 경우, 이러한 상황이 발생할 수 있는 두 가지 상황이 있습니다. 있는경우이를 사용한 적이 brk세그먼트를 사용한 적이 munmap를 해제하는 (세그먼트의 를 들어, 맵된 세그먼트의 방법이 있습니다.) 예를 들어, 다음과 같이.MAP_FIXED당분간MADV_FREE즉시 매핑을 해제하는 세그먼트입니다.)

▁a▁don▁but;다않▁pages▁out를 사용합니다. 그들은 다음을 사용합니다.malloc-style allocator.에 전화할 때.free "" "" "" "" "" "" "" ""일 수 .free매핑(또는 데이터 세그먼트의 마지막 N 페이지)의 마지막 활성 개체를 검색합니다.애플리케이션이 이를 합리적으로 예측하거나 사전에 이를 감지할 수 있는 방법은 없습니다.

Cython은 이를 더욱 복잡하게 만듭니다. 사용자 지정 메모리 할당기 위에 사용자 지정 2-레벨 개체 할당기가 있습니다.malloc(자세한 설명은 소스 주석을 참조하십시오.)게다가 Python은 말할 것도 없고 C API 레벨에서도 최상위 객체의 할당 해제 시기를 직접 제어하지 않습니다.

그렇다면, 객체를 릴리스할 때, OS에 메모리를 릴리스할지 여부를 어떻게 알 수 있습니까?먼저 마지막 참조(모르는 내부 참조 포함)를 릴리스하여 GC가 할당 취소를 허용해야 합니다. (다른 구현과 달리 Cython은 허용되는 즉시 개체 할당을 해제합니다.)은 보통 두 " " " " " 를 하는 것입니다." (" " " " " " " " " " " " " " )를 해제합니다.PyString개체 및 문자열 버퍼).

개체 할당을 취소하는 경우 다음 수준에서 개체 스토리지 블록의 할당을 취소하는지 여부를 확인하려면 개체 할당자의 내부 상태와 구현 방법을 알아야 합니다.(블록에서 마지막 작업의 할당을 해제하지 않는 한 이러한 작업은 발생할 수 없으며, 그 경우에도 발생하지 않을 수 있습니다.)

개체 스토리지 블록의 할당을 취소하는 경우 이로 인해free ( PyMem 다▁a▁within▁(▁call▁,▁in▁)malloced 지역, 그리고 그 때에도, 그것은 일어나지 않을 수 있습니다.)

한다면, free a malloc region, 역지, 이지아알닌지기원것인인을 유발하는지 를 알 수 .munmap이에 하는 (또는 또동등또는(는또동())brk), 의malloc구현 방법에 대해 설명합니다.특별합니다. (으로 사용 . (다리일반마사로로으중할해제용으의야품니해을제당인지막적고품리과)▁(그alloc▁and-▁the▁▁de▁beating▁to▁have▁last합,▁this)malloc에.mmap세그먼트(segment), 그리고 그 때에도, 그것은 일어나지 않을 수 있습니다.)

따라서 정확하게 50.5mb를 릴리스한 이유를 알고 싶다면 아래에서부터 추적해야 합니다.왜 그랬을까요?malloc를 할 때합니다. 하 이 때 할 50.5MB의 페이지 매핑을 해제합니다.free통화(아마도 50.5MB가 조금 넘는 경우)?플랫폼의 내용을 읽어보셔야 합니다.malloc그런 다음 다양한 테이블과 목록을 이동하여 현재 상태를 확인합니다. (일부 플랫폼에서는 오프라인 검사를 위해 시스템 스냅샷을 만들지 않고는 캡처하기가 거의 불가능한 시스템 수준의 정보를 사용할 수도 있지만 다행히도 이는 일반적으로 문제가 되지 않습니다.)그리고 그 위의 3단계에서도 같은 일을 해야 합니다.

그래서, 그 질문에 대한 유일한 유용한 대답은 "왜냐하면"입니다.

리소스 제한(예: 임베디드) 개발을 수행하지 않는 한 이러한 세부 사항에 신경을 쓸 이유가 없습니다.

리소스가 제한된 개발을 수행하는 경우 이러한 세부 정보를 아는 것은 유용하지 않습니다. 이러한 모든 수준에서 특히 최종 실행을 수행해야 합니다.mmap애플리케이션 레벨에서 필요한 메모리(간단하고 잘 이해된 애플리케이션별 영역 할당자를 중간에 하나씩 포함).

먼저 다음을 설치할 수 있습니다.

sudo apt-get install python-pip build-essential python-dev lm-sensors 
sudo pip install psutil logutils bottle batinfo https://bitbucket.org/gleb_zhulik/py3sensors/get/tip.tar.gz zeroconf netifaces pymdstat influxdb elasticsearch potsdb statsd pystache docker-py pysnmp pika py-cpuinfo bernhard
sudo pip install glances

그럼 터미널에서 실행하세요!

glances

Python 코드에서 파일의 시작 부분에 다음을 추가합니다.

import os
import gc # Garbage Collector

메모리를 해제할 "Big" 변수(예: myBigVar)를 사용한 후 파이썬 코드에 다음과 같이 기록합니다.

del myBigVar
gc.collect()

다른 터미널에서 파이썬 코드를 실행하고 시스템에서 메모리가 어떻게 관리되는지 "눈짓" 터미널에서 관찰하십시오!

행운을 빕니다.

추신: 당신은 데비안이나 우분투 시스템에서 일하고 있다고 생각합니다.

언급URL : https://stackoverflow.com/questions/15455048/releasing-memory-in-python

반응형