Este documento descreve como a memória é gerenciada no código traduzido J2ObjC e como os programas se comportam ao acessar a memória compartilhada.
Gerenciamento de memória
Uma das metas do J2ObjC é produzir código traduzido que se integre perfeitamente ao ambiente de contagem de referências do Objective-C. Isso facilita o uso do código Java traduzido do Objective-C escrito nativamente, já que não há transferência de propriedade estranha para objetos transmitidos entre ambientes Java e Objective-C.
Como o Java usa a coleta de lixo para o gerenciamento de memória, o código Java não contém gerenciamento de memória explícito dos objetos. O J2ObjC precisa, portanto, inserir as chamadas de contagem de referência corretamente para garantir que os objetos sejam desalocados no momento certo. Estabelecemos o seguinte conjunto de regras que consideramos eficiente e práticas:
- Todos os objetos permanecerão ativos durante pelo menos a duração do pool de lançamento automático atual.
- Essa regra geral permite pular muitas retenções e versões que seriam necessárias de outra forma.
- As variáveis locais não são mantidas.
- Não há chamadas de contagem de referência em leituras ou gravações de variáveis locais.
- Os campos são mantidos.
- A atribuição de chamadas de campo retém o novo valor e libera automaticamente o valor antigo.
- Os novos objetos são liberados automaticamente imediatamente. (a menos que seja imediatamente atribuído a um campo)
Ciclos de referência
Um ciclo de referência existe quando um objeto se refere a si mesmo direta ou indiretamente usando os campos dele. Os ciclos de referência podem ser limpos pela coleta de lixo do Java, mas vazam memória no ambiente de contagem de referências do Objective-C. Não há uma maneira automatizada de evitar a ocorrência de ciclos de referência. No entanto, oferecemos uma ferramenta Cycle Finder que automatiza a detecção dos ciclos. Veja algumas maneiras comuns de corrigir um ciclo de referência:
- Adicione uma anotação @Weak ou @WeakOuter para enfraquecer uma das referências.
- Adicione um método
cleanup()
a um dos objetos que definem alguns campos como nulos. Chamecleanup()
antes de descartar o objeto. - Projetar o código novamente para evitar a criação de um ciclo de referência.
Memória compartilhada
Em um programa com várias linhas de execução, alguns dados podem ser compartilhados por diversas conversas. O Java oferece várias ferramentas para permitir o acesso seguro para linhas de execução a dados compartilhados. Esta seção descreve o suporte do J2ObjC para acessar dados compartilhados.
Sincronizado
J2ObjC mapeia a palavra-chave synchronized
diretamente para o @synchronized
do Objective-C.
Atomicidade
O Java garante atomicidade para carregamentos e armazenamentos de todos os tipos, exceto long
e double
. Consulte
JLS-17.7 (link em inglês). Com exceção dos
campos volatile
(descritos abaixo), o J2ObjC não fornece tratamento especial para garantir
carregamentos e armazenamentos atômicos. Isso significa o seguinte:
- Como todas as plataformas iOS são de 32 ou 64 bits, os carregamentos e os armazenamentos de tipos primitivos, exceto
long
edouble
, são atômicos em dispositivos de 32 bits, e todos são atômicos em sistemas de 64 bits. - Carregamentos e armazenamentos de tipos de objetos não são atômicos em J2ObjC.
- Atualizar atomicamente as contagens de referência é muito caro.
- Um campo de objeto pode ser atômico declarando-se
volatile
. Veja mais informações abaixo.
Campos voláteis
Para campos volatile
, o Java oferece atomicidade e ordem consistente sequencial (JLS-8.3.1.4), que pode ser usada para sincronização. O J2ObjC fornece as mesmas garantias do Java para todos os campos volatile
.
J2ObjC usa os seguintes mecanismos para campos volatile
:
- Os tipos primitivos são mapeados para tipos atômicos c11.
- Por exemplo:
volatile int
->_Atomic(jint)
- Por exemplo:
- Os campos de objeto são protegidos com bloqueios de mutex do pthread. (não é possível usar bloqueios de rotação devido à inversão de prioridade)
- A exclusão mútua é necessária para evitar disputas com a contagem de referência.
- A implementação é muito semelhante às propriedades atômicas do Objective-C.
Tipos atômicos
O Java fornece vários tipos atômicos no pacote java.util.concurrent.atomic. Todos eles têm suporte total no J2ObjC com implementações personalizadas
Campos finais
O Java garante que uma linha de execução veja valores inicializados nos campos finais de um objeto sem exigir qualquer sincronização ao compartilhar o objeto. (JSL-17.5). No entanto, como o J2ObjC não tem suporte ao acesso atômico de tipos de objetos não voláteis (veja acima), não há uma maneira segura de compartilhar um objeto sem sincronização. Portanto, nenhuma outra restrição é colocada no usuário J2ObjC omitindo os limites de memória necessários para os campos finais.