2009-11-01 2 views
11

다른 코드베이스에서 봤는데 PyMOTW를 읽었을뿐입니다 (첫 번째 노트 here 참고).명시 적으로 sys.exc_info() 추적을 삭제해야하는 이유는 무엇입니까?

트레이스 백이 sys.exc_info()[2]의 변수에 할당 된 경우 사이클이 생성되지만 그 이유는 무엇입니까?

얼마나 큰 문제입니까? 내 코드베이스에서 exc_info의 모든 용도를 검색하고 추적 코드가 삭제되었는지 확인해야합니까?

답변

19

파이썬 3 (원래 대답 업데이트) :

파이썬 3에서 질문에서 인용 조언은 파이썬 문서에서 제거되었습니다. 필자의 원래 답변 (다음 내용)은 설명서에 인용문이 포함 된 Python 버전에만 적용됩니다.

파이썬 2 :

, 결국 찾아 삭제 스택 자체 프레임 중 하나 내부에서 역 추적 스택을 참조하여 만든 것과 같은 순환 참조를, 그렇게하지 않는 것

파이썬 쓰레기 수집기 코드를 다시 작성하십시오. 그러나, 향후, 당신은

http://docs.python.org/library/sys.html

의 조언 (이 문서화 exc_info())를 따라 말할 수 :

exctype, value = sys.exc_info()[:2] 

당신이 예외를 잡아해야 할 때.

두 더 생각 :

첫째, 당신은 왜 모든 exc_info()를 실행?

당신이 예외를 잡을하려면

는 그냥 말을 안 :

try: 
    ... 
except Exception as e: # or "Exception, e" in old Pythons 
    ... do with with e ... 

대신 sys 모듈 내부 개체에 대한 일 처리의?

두 번째 : 좋아요, 많은 조언을했지만 실제로 질문에 답변하지 않았습니다.:-)

주기가 생성되는 이유는 무엇입니까?

a = [1,2,3] 
a.append(a) 

두 개체가 서로를 참조 할 때 : 음, 간단한 경우에, 사이클이 생성되는 객체 그 자체를 의미 할 때

두 경우 모두
a = [1,2,3] 
b = [4,5,a] 
a.append(b) 

때 함수 단부 변수 값은 참조 카운트 포옹에 잠겨 있기 때문에 여전히 존재합니다. 다른 변수가 먼저 사라질 때까지 사라지지 않습니다! 결국 현대 파이썬 가비지 컬렉터 만이이를 해결할 수 있습니다. 결국 루프를 알아 차리고 깨뜨리는 것입니다.

이 상황을 이해하는 열쇠는 exc_info()에 의해 반환 된 세 번째 것 (인덱스 # 2)이 예외가 호출되었을 때 활성화 된 각 함수에 대한 "스택 프레임"을 포함한다는 것입니다 . 그리고 해당 스택 프레임은 이 아니며 "dead"객체는 인 것을 보여줍니다. 프레임은 아직 살아 있습니다! 예외를 잡은 함수는 여전히 살아 있기 때문에 스택 프레임은 살아있는 것입니다. 예외를 처리하기 위해 코드가 실행될 때 변수 참조가 계속 증가하고 손실됩니다 (예외를 완료하고 실행하는 다른 작업을 수행하고 이동합니다). 그 일에 대해).

t = sys.exc_info()[2]라고하면 역 추적 내부에있는 스택 프레임 중 하나 (사실 현재 실행중인 바로 그 함수에 속한 프레임)에 스택 프레임을 다시 가리키는 변수 t이 있습니다. 그 자체로, 위에서 보여준 것과 같은 루프를 만듭니다.

+1

[경고 :]'[: 2]'사용에 대한 조언으로 언급 한 [Python 3.3. 이유는 [# 7340] (https://bugs.python.org/issue7340)에 설명되어 있습니다. '[: 2] '트릭은 더 이상 작동하지 않으므로 처리 된 예외의'__traceback__' 속성을 대신 'None'으로 설정해야합니다. 관련 PEP : [344] (https://www.python.org/dev/peps/pep-0344/#open-issue-garbage-collection), [3134] (https://www.python.org/dev/peps/pep-3134/# open-issue-garbage-collection), [3110] (https://www.python.org/dev/peps/pep-3110/#semantic-changes). – Delgan

10

추적에는 모든 활성 프레임에 대한 참조가 포함되어 있습니다.이 활성 프레임은 다양한 프레임의 모든 로컬 변수에 대한 참조를 포함합니다. 이러한 참조는 추적 및 프레임 객체의 역할 중 가장 중요한 부분이므로 매우 놀랍습니다 . 따라서 추적을 다시 참조에 추가하면 (또는 일시적으로 추가 한 상태에서 신속하게 제거하지 못하면) 필연적으로 참조 루프가 형성되어 가비지 수집을 방해하게됩니다 (개체 중 하나가 루프에서 __del__, 종결 자 메소드를 넘어서는 클래스에 속함).

특히 장기 실행 프로그램에서 가비지 수집을 방해하는 것이 가장 좋은 아이디어는 아닙니다. 필요하지 않은 메모리를 계속 보유하게 될 것이기 때문에 (필요 이상으로 길게 또는 무기한으로 finalizers가있는 객체를 포함시킴으로써 이러한 루프에서 가비지 컬렉션을 기본적으로 차단합니다.

exc_info에서 왔는지 여부에 관계없이 최대한 빨리 가능한 한 빨리 추적 코드를 제거하는 것이 가장 좋습니다!

관련 문제