Vamos começar com retain
e release
; autorelease
é realmente apenas um caso especial quando você entende os conceitos básicos.
No Cocoa, cada objeto controla quantas vezes está sendo referenciado (especificamente, a NSObject
classe base implementa isso). Ao chamar retain
um objeto, você está dizendo que deseja aumentar a contagem de referências em um. Ao ligar release
, você diz ao objeto que o está soltando e sua contagem de referência é diminuída. Se, após a chamada release
, a contagem de referência agora for zero, a memória desse objeto será liberada pelo sistema.
A maneira básica pela qual isso difere malloc
e free
é que um determinado objeto não precisa se preocupar com o travamento de outras partes do sistema, porque você liberou a memória que eles estavam usando. Supondo que todos estejam jogando junto e mantendo / liberando de acordo com as regras, quando um trecho de código retém e depois libera o objeto, qualquer outro trecho de código que também faça referência ao objeto não será afetado.
O que às vezes pode ser confuso é conhecer as circunstâncias em que você deve ligar retain
e release
. Minha regra geral é que, se eu quiser me apegar a um objeto por algum tempo (se for uma variável de membro de uma classe, por exemplo), preciso garantir que a contagem de referência do objeto saiba de mim. Como descrito acima, a contagem de referência de um objeto é incrementada chamando retain
. Por convenção, também é incrementado (realmente definido como 1) quando o objeto é criado com um método "init". Em qualquer um desses casos, é minha responsabilidade chamar release
o objeto quando terminar. Caso contrário, haverá um vazamento de memória.
Exemplo de criação de objeto:
NSString* s = [[NSString alloc] init]; // Ref count is 1
[s retain]; // Ref count is 2 - silly
// to do this after init
[s release]; // Ref count is back to 1
[s release]; // Ref count is 0, object is freed
Agora para autorelease
. A liberação automática é usada como uma maneira conveniente (e às vezes necessária) de instruir o sistema a liberar esse objeto depois de um tempo. Do ponto de vista do encanamento, quando autorelease
é chamado, o encadeamento atual NSAutoreleasePool
é alertado sobre a chamada. O NSAutoreleasePool
agora sabe que, quando obtiver uma oportunidade (após a iteração atual do loop de eventos), poderá chamar release
o objeto. Do nosso ponto de vista como programadores, ele cuida de release
nos chamar , para que não precisemos (e de fato não deveríamos).
O que é importante observar é que (novamente, por convenção) todos os métodos de classe de criação de objeto retornam um objeto liberado automaticamente. Por exemplo, no exemplo a seguir, a variável "s" tem uma contagem de referência 1, mas após a conclusão do loop de eventos, ela será destruída.
NSString* s = [NSString stringWithString:@"Hello World"];
Se você deseja pendurar nessa sequência, precisará chamar retain
explicitamente e, em seguida, explicitamente release
quando terminar.
Considere o seguinte código (muito elaborado) de código e você verá uma situação em que autorelease
é necessário:
- (NSString*)createHelloWorldString
{
NSString* s = [[NSString alloc] initWithString:@"Hello World"];
// Now what? We want to return s, but we've upped its reference count.
// The caller shouldn't be responsible for releasing it, since we're the
// ones that created it. If we call release, however, the reference
// count will hit zero and bad memory will be returned to the caller.
// The answer is to call autorelease before returning the string. By
// explicitly calling autorelease, we pass the responsibility for
// releasing the string on to the thread's NSAutoreleasePool, which will
// happen at some later time. The consequence is that the returned string
// will still be valid for the caller of this function.
return [s autorelease];
}
Sei que tudo isso é um pouco confuso - em algum momento, porém, ele clicará. Aqui estão algumas referências para você começar:
- Introdução da Apple ao gerenciamento de memória.
- Cocoa Programming for Mac OS X (4ª Edição) , de Aaron Hillegas - um livro muito bem escrito, com muitos ótimos exemplos. Lê como um tutorial.
- Se você está realmente mergulhando, pode ir para o Big Nerd Ranch . Esta é uma instalação de treinamento administrada por Aaron Hillegas - o autor do livro mencionado acima. Eu participei do curso Introdução ao cacau lá há vários anos e foi uma ótima maneira de aprender.
NSString* s = [[NSString alloc] initWithString:@"Hello World"];
retorna um objeto liberado automaticamente (como você o escreve), por que eu tenho que fazer umreturn [s autorelease];
e defini-lo como "autorelease" novamente e não apenasreturn s
?[[NSString alloc] initWithString:@"Hello World"]
NÃO retornará um objeto liberado automaticamente . Sempre quealloc
é chamado, a contagem de referência é definida como 1 e é de responsabilidade desse código garantir que ele seja liberado. A[NSString stringWithString:]
chamada, por outro lado, não retornar um objeto autoreleased.Se você entende o processo de retenção / liberação, existem duas regras de ouro que são "duh" óbvias para os programadores estabelecidos do Cocoa, mas infelizmente raramente são explicadas claramente para os novatos.
Se uma função que retorna um objeto possui
alloc
,create
oucopy
em seu nome, o objeto é seu. Você deve ligar[object release]
quando terminar. OuCFRelease(object)
, se for um objeto Core-Foundation.Se NÃO tiver uma dessas palavras em seu nome, o objeto pertence a outra pessoa. Você deve ligar
[object retain]
se desejar manter o objeto após o término de sua função.Você estaria bem servido também para seguir esta convenção nas funções que você mesmo criar.
(Nitpickers: Sim, infelizmente existem algumas chamadas de API que são exceções a essas regras, mas são raras).
fonte
Se você está escrevendo um código para a área de trabalho e pode segmentar o Mac OS X 10.5, deve pelo menos examinar a coleta de lixo do Objective-C. Ele realmente simplificará a maior parte do seu desenvolvimento - é por isso que a Apple se esforça ao máximo para criá-lo e fazê-lo funcionar bem.
Quanto às regras de gerenciamento de memória quando não estiver usando o GC:
+alloc/+allocWithZone:
,+new
,-copy
ou-mutableCopy
ou se-retain
um objeto, você está tomando posse dela e deve garantir que ele é enviado-release
.-release
.-release
você mesmo pode enviá-lo ou o objeto-autorelease
e o pool de liberação automática atual o enviará-release
(uma vez por recebido-autorelease
) quando o pool for drenado.Normalmente,
-autorelease
é usado como uma maneira de garantir que os objetos permaneçam durante todo o evento atual, mas sejam limpos posteriormente, pois há um pool de liberação automática que envolve o processamento de eventos do Cocoa. No cacau, é muito mais comum retornar objetos a um chamador que é liberado automaticamente do que retornar objetos que o próprio chamador precisa liberar.fonte
O Objective-C usa a Contagem de referência , o que significa que cada Objeto tem uma contagem de referência. Quando um objeto é criado, ele tem uma contagem de referência "1". Simplesmente falando, quando um objeto é referido (ou seja, armazenado em algum lugar), ele é "retido", o que significa que sua contagem de referência é aumentada em um. Quando um objeto não é mais necessário, ele é "liberado", o que significa que sua contagem de referência é reduzida em um.
Quando a contagem de referência de um objeto é 0, o objeto é liberado. Esta é a contagem básica de referência.
Para alguns idiomas, as referências são automaticamente aumentadas e diminuídas, mas o objetivo-c não é um desses idiomas. Assim, o programador é responsável por reter e liberar.
Uma maneira típica de escrever um método é:
O problema de precisar lembrar de liberar quaisquer recursos adquiridos dentro do código é tedioso e propenso a erros. O Objective-C apresenta outro conceito que visa facilitar isso: pools de liberação automática. Conjuntos de liberação automática são objetos especiais instalados em cada encadeamento. Eles são uma classe bastante simples, se você procurar NSAutoreleasePool.
Quando um objeto recebe uma mensagem de "autorelease" enviada a ele, o objeto procurará por todos os pools de autorelease na pilha para esse thread atual. Ele adicionará o objeto à lista como um objeto para o qual enviará uma mensagem de "release" em algum momento no futuro, que geralmente ocorre quando o próprio pool é liberado.
Tomando o código acima, você pode reescrevê-lo para ser mais curto e fácil de ler, dizendo:
Como o objeto é liberado automaticamente, não precisamos mais chamar explicitamente "release". Isso ocorre porque sabemos que algum pool de autorelease fará isso por nós mais tarde.
Espero que isso ajude. O artigo da Wikipedia é muito bom sobre a contagem de referências. Mais informações sobre pools de autorelease podem ser encontradas aqui . Observe também que, se você estiver construindo para o Mac OS X 10.5 e posterior, pode pedir ao Xcode para construir com a coleta de lixo ativada, permitindo ignorar completamente reter / liberar / liberação automática.
fonte
Joshua (# 6591) - O material de coleta de lixo no Mac OS X 10.5 parece bem legal, mas não está disponível para o iPhone (ou se você deseja que o aplicativo seja executado nas versões anteriores ao 10.5 do Mac OS X).
Além disso, se você estiver escrevendo uma biblioteca ou algo que possa ser reutilizado, o uso do modo GC impede que qualquer pessoa que use o código também use o modo GC, pelo que entendi, qualquer pessoa que tente escrever código amplamente reutilizável tende a gerenciar memória manualmente.
fonte
Como sempre, quando as pessoas começam a tentar reformular o material de referência, quase invariavelmente entendem algo errado ou fornecem uma descrição incompleta.
A Apple fornece uma descrição completa do sistema de gerenciamento de memória do Cocoa no Memory Management Programming Guide for Cocoa , no final do qual existe um resumo breve, porém preciso, das Regras de gerenciamento de memória .
fonte
Não adicionarei detalhes específicos de retenção / liberação, a menos que você queira gastar US $ 50 e obter o livro Hillegass, mas eu sugiro enfaticamente que você use as ferramentas Instruments muito cedo no desenvolvimento de seu aplicativo (até mesmo o seu primeiro!). Para fazer isso, execute-> Iniciar com ferramentas de desempenho. Eu começaria com o Leaks, que é apenas um dos muitos instrumentos disponíveis, mas ajudará a mostrar quando você se esquecer de lançar. É assustador quanta informação você será apresentado. Mas confira este tutorial para acelerar e acelerar:
TUTORIAL DE CACAU: CONSERVANDO FUGAS DE MEMÓRIA COM INSTRUMENTOS
Na verdade, tentar forçar vazamentos pode ser uma maneira melhor de aprender a evitá-los! Boa sorte ;)
fonte
A liberação automática não retém o objeto. O lançamento automático simplesmente o coloca na fila para ser lançado posteriormente. Você não deseja ter uma declaração de lançamento lá.
fonte
Minha coleção habitual de artigos sobre gerenciamento de memória Cocoa:
gerenciamento de memória de cacau
fonte
Há um screencast gratuito disponível na Rede iDeveloperTV
Gerenciamento de memória no Objective-C
fonte
A resposta do NilObject é um bom começo. Aqui estão algumas informações adicionais referentes ao gerenciamento manual de memória ( necessário no iPhone ).
Se você pessoalmente
alloc/init
um objeto, ele vem com uma contagem de referência de 1. Você é responsável por limpá-lo quando ele não for mais necessário, ligando[foo release]
ou[foo autorelease]
. A liberação o limpa imediatamente, enquanto a liberação automática adiciona o objeto ao pool de liberação automática, que a liberará automaticamente posteriormente.autorelease é principalmente para quando você tem um método que precisa retornar o objeto em questão ( para que você não possa liberá-lo manualmente, caso contrário, retornará um objeto nulo ), mas também não deseja segurá-lo. .
Se você adquirir um objeto em que não chamou aloc / init para obtê-lo - por exemplo:
mas você quer se apegar a esse objeto, precisa chamar [foo reter]. Caso contrário, é possível que ele aconteça
autoreleased
e você manterá uma referência nula (como seria nostringWithString
exemplo acima ). Quando você não precisar mais dele, ligue[foo release]
.fonte
As respostas acima fornecem reformulações claras do que a documentação diz; o problema em que a maioria das novas pessoas se depara são os casos não documentados. Por exemplo:
Autorelease : os documentos dizem que o lançamento será "em algum momento no futuro". QUANDO?! Basicamente, você pode contar com o objeto existente até sair do código de volta ao loop de eventos do sistema. O sistema pode liberar o objeto a qualquer momento após o ciclo de eventos atual. (Acho que Matt disse isso antes.)
Cordas estáticas :
NSString *foo = @"bar";
- você precisa reter ou liberar isso? Não. Que tal...
A regra de criação : se você o criou, é o proprietário e espera-se lançá-lo.
Em geral, a maneira como os novos programadores do Cocoa são confusos é não entender quais rotinas retornam um objeto com a
retainCount > 0
.Aqui está um trecho de Regras muito simples para gerenciamento de memória no cacau :
O primeiro marcador diz: se você ligou
alloc
(ounew fooCopy
), precisa chamar release nesse objeto.O segundo marcador diz: se você usa um construtor de conveniência e precisa que o objeto fique por perto (como em uma imagem a ser desenhada posteriormente), é necessário retê-lo (e depois liberá-lo).
O terceiro deve ser auto-explicativo.
fonte
Muitas informações boas sobre cocoadev também:
fonte
Como várias pessoas já mencionaram, a introdução ao gerenciamento de memória da Apple é de longe o melhor lugar para começar.
Um link útil que ainda não vi mencionado é o Gerenciamento prático de memória . Você o encontrará no meio dos documentos da Apple, se os ler, mas vale a pena vincular diretamente. É um resumo executivo brilhante das regras de gerenciamento de memória com exemplos e erros comuns (basicamente o que outras respostas aqui estão tentando explicar, mas não tão bem).
fonte