2011-12-31 5 views
2

내가 다음은 내 코드에서 많이 사용 작은 편리한 클래스가 수집 못하고 :순환 참조 된 개체는 쓰레기

class Structure(dict): 
    def __init__(self, **kwargs): 
     dict.__init__(self, **kwargs) 
     self.__dict__ = self 

그것의 좋은 점은 사용 속성에 액세스 할 수 있습니다 것입니다 사전 키 구문 또는 일반적인 개체 스타일 :

myStructure = Structure(name="My Structure") 
print myStructure["name"] 
print myStructure.name 

오늘 나는 내 응용 프로그램 메모리 소비가 감소 할 것으로 예상했던 상황에서 약간 증가하고있는 것으로 나타났습니다. 구조체 클래스에서 생성 된 인스턴스는 수집 된 garbaged 지 않습니다. 다음과 같은 출력으로

import gc 

class Structure(dict): 
    def __init__(self, **kwargs): 
     dict.__init__(self, **kwargs) 
     self.__dict__ = self 

structures = [Structure(name="__{0}".format(str(value))) for value in range(4096)] 
print "Structure name: ", structures[16].name 
print "Structure name: ", structures[16]["name"] 
del structures 
gc.collect() 
print "Structures count: ", len([obj for obj in gc.get_objects() if type(obj) is Structure]) 

:

Structure name: __16 
Structure name: __16 
Structures count: 4096 

당신이 인스턴스 카운트 구조 발견으로 내가 작성할 때는 줄을 주석 4096

여전히 여기를 설명하는 것은 작은 조각이다 편리한 자체 참조 :

import gc 

class Structure(dict): 
    def __init__(self, **kwargs): 
     dict.__init__(self, **kwargs) 
     # self.__dict__ = self 

structures = [Structure(name="__{0}".format(str(value))) for value in range(4096)] 
# print "Structure name: ", structures[16].name 
print "Structure name: ", structures[16]["name"] 
del structures 
gc.collect() 
print "Structures count: ", len([obj for obj in gc.get_objects() if type(obj) is Structure]) 
다음 출력을 생성

import gc 
import pprint 
from meliae import scanner 
from meliae import loader 

class Structure(dict): 
    def __init__(self, **kwargs): 
     dict.__init__(self, **kwargs) 
     self.__dict__ = self 

structures = [Structure(name="__{0}".format(str(value))) for value in range(4096)] 
print "Structure name: ", structures[16].name 
print "Structure name: ", structures[16]["name"] 
del structures 
gc.collect() 
print "Structures count: ", len([obj for obj in gc.get_objects() if type(obj) is Structure]) 

scanner.dump_all_objects("Test_001.json") 
om = loader.load("Test_001.json") 
summary = om.summarize() 
print summary 

structures = om.get_all("Structure") 
if structures: 
    pprint.pprint(structures[0].c) 

:

Structure name: __16 
Structures count: 0 

내가 약간 상기 메모리 사용을 분석 Melia을 사용하여 테스트를 밀어 :이제 원형 기준 출력을 제거되는 것을 의미한다

Structure name: __16 
Structure name: __16 
Structures count: 4096 
loading... line 5001, 5002 objs, 0.6/ 1.8 MiB read in 0.2s 
loading... line 10002, 10003 objs, 1.1/ 1.8 MiB read in 0.3s 
loading... line 15003, 15004 objs, 1.7/ 1.8 MiB read in 0.5s 
loaded line 16405, 16406 objs, 1.8/ 1.8 MiB read in 0.5s   
checked  1/ 16406 collapsed  0  
checked 16405/ 16406 collapsed  157  
compute parents  0/ 16249   
compute parents 16248/ 16249   
set parents 16248/ 16249   
collapsed in 0.2s 
Total 16249 objects, 58 types, Total size = 3.2MiB (3306183 bytes) 
Index Count %  Size % Cum  Max Kind 
    0 4096 25 1212416 36 36  296 Structure 
    1  390 2 536976 16 52 49432 dict 
    2 5135 31 417550 12 65 12479 str 
    3  82 0 290976 8 74 12624 module 
    4  235 1 212440 6 80  904 type 
    5  947 5 121216 3 84  128 code 
    6 1008 6 120960 3 88  120 function 
    7 1048 6  83840 2 90  80 wrapper_descriptor 
    8  654 4  47088 1 92  72 builtin_function_or_method 
    9  562 3  40464 1 93  72 method_descriptor 
    10  517 3  37008 1 94  216 tuple 
    11  139 0  35832 1 95 2280 set 
    12  351 2  30888 0 96  88 weakref 
    13  186 1  23200 0 97 1664 list 
    14  63 0  21672 0 97  344 WeakSet 
    15  21 0  18984 0 98  904 ABCMeta 
    16  197 1  14184 0 98  72 member_descriptor 
    17  188 1  13536 0 99  72 getset_descriptor 
    18  284 1  6816 0 99  24 int 
    19  14 0  5296 0 99 2280 frozenset 
[Structure(4312707312 296B 2refs 2par), 
type(4298634592 904B 4refs 100par 'Structure')] 

메모리 사용량이 3.2MiB이므로 자기 참조 선을 제거하면 다음 출력으로 연결됩니다.

Structure name: __16 
Structures count: 0 
loading... line 5001, 5002 objs, 0.6/ 1.4 MiB read in 0.1s 
loading... line 10002, 10003 objs, 1.1/ 1.4 MiB read in 0.3s 
loaded line 12308, 12309 objs, 1.4/ 1.4 MiB read in 0.4s   
checked  12/ 12309 collapsed  0  
checked 12308/ 12309 collapsed  157  
compute parents  0/ 12152   
compute parents 12151/ 12152   
set parents 12151/ 12152   
collapsed in 0.1s 
Total 12152 objects, 57 types, Total size = 2.0MiB (2093714 bytes) 
Index Count %  Size % Cum  Max Kind 
    0  390 3 536976 25 25 49432 dict 
    1 5134 42 417497 19 45 12479 str 
    2  82 0 290976 13 59 12624 module 
    3  235 1 212440 10 69  904 type 
    4  947 7 121216 5 75  128 code 
    5 1008 8 120960 5 81  120 function 
    6 1048 8  83840 4 85  80 wrapper_descriptor 
    7  654 5  47088 2 87  72 builtin_function_or_method 
    8  562 4  40464 1 89  72 method_descriptor 
    9  517 4  37008 1 91  216 tuple 
    10  139 1  35832 1 92 2280 set 
    11  351 2  30888 1 94  88 weakref 
    12  186 1  23200 1 95 1664 list 
    13  63 0  21672 1 96  344 WeakSet 
    14  21 0  18984 0 97  904 ABCMeta 
    15  197 1  14184 0 98  72 member_descriptor 
    16  188 1  13536 0 98  72 getset_descriptor 
    17  284 2  6816 0 99  24 int 
    18  14 0  5296 0 99 2280 frozenset 
    19  22 0  2288 0 99  104 classobj 

구조체 인스턴스가 파괴되었으며 메모리 사용량이 2.0MiB로 감소했는지 확인합니다.

이 클래스가 제대로 가비지 수집되도록하려면 어떻게 생각하세요? 이 모든 것은 Python 2.7.2 (Darwin)에서 실행됩니다.

건배,

토마스

+0

왜 자체 참조를 원하십니까? 속성 액세스 및 항목 조회 (IMHO 및 Python의 Zen에 따르면 나쁜 아이디어)의 이중성을 주장하더라도이 목표를 달성하는 데있어 훨씬 나은, 덜 해킹 된 방법이 있습니다. – delnan

답변

3

당신은 더 노골적 속성 액세스가 기본이 DICT에 갈 수 있도록 __getattr____setattr__를 사용하여 구조를 구현하고 있습니다.

class Structure(dict): 
    def __getattr__(self, k): 
     return self[k] 
    def __setattr__(self, k, v): 
     self[k] = v 

사이클 쓰레기를 파이썬에서 수집,하지만 주기적으로 (자신의 참조 카운트 즉시 수집 얻을 일반 참조 카운트 객체는 달리 공에 방울)된다.

사이클을 피하려면 (__getattr____setattr__을 사용하는 Structure 클래스처럼) 더 나은 gc 동작을 얻을 수 있습니다.좋은 대안으로 collections.namedtuple을보고 싶을 수도 있습니다. 구현 한 것과 정확히 일치하지는 않지만 귀하의 목적에 어울릴 수 있습니다.

+0

하이 폴, 건배! 좋은 대안 인 것 같습니다. 실제로이 게시물에서 그것에 대해 읽었습니다. http://ruslanspivak.com/2011/06/12/the-bunch-pattern/. 분명히 가비지 수집 버그도 알려져 있습니다 : http://bugs.python.org/issue1469629 namedTuple에 대해서 : 나는 그 목적을 위해 오래전에 살펴 봤지만 데이터가 변경 가능해야합니다. –