Ciclo de vida do objeto¶
Esta seção explica como os slots de um tipo se relacionam entre si ao longo da vida de um objeto. Não se destina a ser uma referência canônica completa para os slots; em vez disso, consulte a documentação específica do slot em Estruturas de objetos tipo para obter detalhes sobre um slot específico.
Eventos de vida¶
A figura abaixo ilustra a ordem dos eventos que podem ocorrer ao longo da vida de um objeto. Uma seta de A para B indica que o evento B pode ocorrer após a ocorrência do evento A, com o rótulo da seta indicando a condição que deve ser verdadeira para que B ocorra após A.
Explicação:
Quando um novo objeto é construído chamando seu tipo:
tp_newé chamado para criar um novo objeto.tp_allocé chamado diretamente portp_newpara alocar a memória para o novo objeto.tp_initinicializa o objeto recém-criado.tp_initpode ser chamado novamente para reinicializar um objeto, se desejado. A chamada DEtp_inittambém pode ser completamente ignorada, por exemplo, com código Python chamando__new__().
Após a conclusão de
tp_init, o objeto estará pronto para uso.Algum tempo após a última referência a um objeto ser removida:
Se um objeto não estiver marcado como finalizado, ele poderá ser finalizado marcando-o como finalizado e chamando sua função
tp_finalize. O Python não finaliza um objeto quando a última referência a ele é excluída; usePyObject_CallFinalizerFromDealloc()para garantir quetp_finalizeseja sempre chamado.Se o objeto estiver marcado como finalizado,
tp_clearpoderá ser chamado pelo coletor de lixo para limpar as referências mantidas pelo objeto. Ele não é chamado quando a contagem de referências do objeto chega a zero.tp_deallocé chamado para destruir o objeto. Para evitar duplicação de código,tp_deallocnormalmente chamatp_clearpara liberar as referências do objeto.Quando
tp_dealloctermina a destruição do objeto, ele chama diretamentetp_free(geralmente definido comoPyObject_Free()ouPyObject_GC_Del()automaticamente, conforme apropriado para o tipo) para desalocar a memória.
A função
tp_finalizetem permissão para adicionar uma referência ao objeto, se desejado. Se isso acontecer, o objeto será ressuscitado, impedindo sua destruição pendente. (Somentetp_finalizetem permissão para ressuscitar um objeto;tp_clearetp_deallocnão podem sem chamartp_finalize.) Ressuscitar um objeto pode ou não causar a remoção da marca finalizado do objeto. Atualmente, o Python não remove a marca finalizado de um objeto ressuscitado se ele suportar coleta de lixo (ou seja, o sinalizadorPy_TPFLAGS_HAVE_GCestiver definido), mas remove a marca se o objeto não suportar coleta de lixo; qualquer um ou ambos os comportamentos podem mudar no futuro.tp_deallocpode opcionalmente chamartp_finalizeviaPyObject_CallFinalizerFromDealloc()se desejar reutilizar esse código para auxiliar na destruição de objetos. Isso é recomendado porque garante quetp_finalizeseja sempre chamado antes da destruição. Consulte a documentação detp_deallocpara obter um exemplo de código.Se o objeto for membro de um isolado cíclico e
tp_clearnão conseguir interromper o ciclo de referência ou o isolado cíclico não for detectado (talvezgc.disable()tenha sido chamado ou o sinalizadorPy_TPFLAGS_HAVE_GCtenha sido omitido erroneamente em um dos tipos envolvidos), os objetos permanecerão indefinidamente não coletáveis (eles “vazam”). Vejagc.garbage.
Se o objeto for marcado como compatível com coleta de lixo (o sinalizador Py_TPFLAGS_HAVE_GC estiver definido em tp_flags), os seguintes eventos também serão possíveis:
O coletor de lixo ocasionalmente chama
tp_traversepara identificar isolados cíclicos.Quando o coletor de lixo descobre um isolado cíclico, ele finaliza um dos objetos do grupo marcando-o como finalizado e chamando sua função
tp_finalize, se houver. Isso se repete até que o isolado cíclico não exista mais ou todos os objetos tenham sido finalizados.tp_finalizetem permissão para ressuscitar o objeto adicionando uma referência externa ao isolado cíclico. A nova referência faz com que o grupo de objetos não forme mais um isolado cíclico (o ciclo de referência ainda pode existir, mas se existir, os objetos não estarão mais isolados).Quando o coletor de lixo descobre um isolado cíclico e todos os objetos do grupo já foram marcados como finalizados, o coletor de lixo limpa um ou mais objetos não limpos no grupo (possivelmente simultaneamente) chamando a função
tp_clearde cada um. Isso se repete enquanto o isolado cíclico ainda existir e nem todos os objetos tiverem sido limpos.
Destruição de isolado cíclico¶
Abaixo estão listados os estágios de vida de um isolado cíclico hipotético que continua a existir após cada objeto membro ser finalizado ou limpo. É um vazamento de memória se um isolado cíclico passar por todos esses estágios; ele deve desaparecer assim que todos os objetos forem limpos, ou até mesmo antes. Um isolado cíclico pode desaparecer porque o ciclo de referência foi quebrado ou porque os objetos não estão mais isolados devido à ressurreição do finalizador (veja tp_finalize).
Alcançável (ainda não é um isolado cíclico): todos os objetos estão em seu estado normal e acessível. Um ciclo de referência pode existir, mas uma referência externa significa que os objetos ainda não estão isolados.
Inalcançável, mas consistente: a referência final de fora do grupo cíclico de objetos foi removida, causando o isolado dos objetos (criando assim um isolado cíclico). Nenhum dos objetos do grupo foi finalizado ou limpo ainda. O isolado cíclico permanece neste estágio até alguma execução futura do coletor de lixo (não necessariamente a próxima execução, pois a próxima execução pode não varrer todos os objetos).
Mistura de finalizados e não finalizados: objetos em um isolado cíclico são finalizados um de cada vez, o que significa que há um período em que o isolado cíclico é composto por uma mistura de objetos finalizados e não finalizados. A ordem de finalização não é especificada, portanto, pode parecer aleatória. Um objeto finalizado deve se comportar de maneira sensata quando objetos não finalizados interagem com ele, e um objeto não finalizado deve ser capaz de tolerar a finalização de um subconjunto arbitrário de seus referentes.
Todos finalizados: todos os objetos em um isolado cíclico são finalizados antes que qualquer um deles seja limpo.
Combinação de finalizado e limpo: os objetos podem ser limpos em série ou simultaneamente (mas com a GIL mantida); de qualquer forma, alguns serão concluídos antes de outros. Um objeto finalizado deve ser capaz de tolerar a limpeza de um subconjunto de seus referentes. PEP 442 chama essa etapa de “lixo cíclico”.
Vazamento: se um isolado cíclico ainda existir após todos os objetos do grupo terem sido finalizados e limpos, os objetos permanecerão indefinidamente não coletáveis (consulte
gc.garbage). É um bug se um isolado cíclico atingir esse estágio — significa que os métodostp_cleardos objetos participantes falharam em interromper o ciclo de referência conforme necessário.
Se tp_clear não existisse, o Python não teria como interromper com segurança um ciclo de referência. A simples destruição de um objeto em um isolado cíclico resultaria em um ponteiro pendente, desencadeando um comportamento indefinido quando um objeto que referencia o objeto destruído é destruído. A etapa de limpeza torna a destruição de objetos um processo de duas fases: primeiro, tp_clear é chamado para destruir parcialmente os objetos o suficiente para desvinculá-los uns dos outros; em seguida, tp_dealloc é chamado para completar a destruição.
Ao contrário da limpeza, a finalização não é uma fase da destruição. Um objeto finalizado ainda deve se comportar corretamente, continuando a cumprir seus contratos de design. O finalizador de um objeto pode executar código Python arbitrário e até mesmo impedir a destruição iminente adicionando uma referência. O finalizador está relacionado à destruição apenas pela ordem de chamada — se for executado, será executado antes da destruição, que começa com tp_clear (se chamado) e termina com tp_dealloc.
A etapa de finalização não é necessária para recuperar com segurança os objetos em um isolado cíclico, mas sua existência facilita o design de tipos que se comportam de maneira sensata quando os objetos são limpos. Limpar um objeto pode necessariamente deixá-lo em um estado quebrado, parcialmente destruído — pode ser inseguro chamar qualquer um dos métodos do objeto limpo ou acessar qualquer um de seus atributos. Com a finalização, apenas objetos finalizados podem interagir com objetos limpos; objetos não finalizados têm a garantia de interagir apenas com objetos não limpos (mas potencialmente finalizados).
Para resumir as interações possíveis:
Um objeto não finalizado pode ter referências a ou de objetos não finalizados e finalizados, mas não a ou de objetos limpos.
Um objeto finalizado pode ter referências a ou de objetos não finalizados, finalizados e limpos.
Um objeto limpo pode ter referências a ou de objetos finalizados e limpos, mas não a ou de objetos não finalizados.
Sem ciclos de referência, um objeto pode ser simplesmente destruído após a exclusão de sua última referência; as etapas de finalização e limpeza não são necessárias para recuperar objetos não utilizados com segurança. No entanto, pode ser útil chamar automaticamente tp_finalize e tp_clear antes da destruição, pois o design de tipos é simplificado quando todos os objetos sempre experimentam a mesma série de eventos, independentemente de terem participado ou não de um isolado cíclico. Atualmente, o Python chama tp_finalize e tp_clear apenas conforme necessário para destruir um isolado cíclico; isso pode mudar em uma versão futura.
Funções¶
Para alocar e liberar memória, consulte Alocando objetos na heap.
-
void PyObject_CallFinalizer(PyObject *op)¶
Finaliza o objeto conforme descrito em
tp_finalize. Chame esta função (ouPyObject_CallFinalizerFromDealloc()) em vez de chamartp_finalizediretamente, pois esta função pode desduplicar várias chamadas paratp_finalize. Atualmente, as chamadas são desduplicadas somente se o tipo oferecer suporte a coleta de lixo (ou seja, se o sinalizadorPy_TPFLAGS_HAVE_GCestiver definido); isso pode mudar no futuro.
-
int PyObject_CallFinalizerFromDealloc(PyObject *op)¶
O mesmo que
PyObject_CallFinalizer(), mas deve ser chamado no início do destrutor do objeto (tp_dealloc). Não deve haver nenhuma referência ao objeto. Se o finalizador do objeto ressuscitar o objeto, esta função retornará -1; nenhuma outra destruição deverá ocorrer. Caso contrário, esta função retornará 0 e a destruição pode continuar normalmente.Ver também
tp_deallocpara código de exemplo.