Sinal EXC_BAD_ACCESS recebido

290

Ao implantar o aplicativo no dispositivo, o programa será encerrado após alguns ciclos com o seguinte erro:

Program received signal: "EXC_BAD_ACCESS".

O programa é executado sem nenhum problema no simulador do iPhone, ele também irá depurar e executar desde que eu siga as instruções, uma de cada vez. Assim que eu deixá-lo funcionar novamente, atingirei o EXC_BAD_ACCESSsinal.

Nesse caso em particular, ocorreu um erro no código do acelerômetro. Não seria executado dentro do simulador, razão pela qual não gerou nenhum erro. No entanto, ele seria executado uma vez implantado no dispositivo.

A maioria das respostas para esta pergunta lida com o EXC_BAD_ACCESSerro geral , por isso deixarei em aberto como um exemplo para o temido erro de mau acesso.

EXC_BAD_ACCESSnormalmente é lançado como resultado de um acesso ilegal à memória. Você pode encontrar mais informações nas respostas abaixo.

Você já encontrou o EXC_BAD_ACCESSsinal antes e como lidou com isso?

Héctor Ramos
fonte

Respostas:

196

Pela sua descrição, suspeito que a explicação mais provável seja que você tenha algum erro no gerenciamento de memória. Você disse que trabalha no desenvolvimento do iPhone há algumas semanas, mas não se tem experiência com o Objetivo C em geral. Se você veio de outro plano de fundo, pode demorar um pouco até você realmente internalizar as regras de gerenciamento de memória - a menos que você faça um grande sentido.

Lembre-se de que tudo o que você obtém de uma função de alocação (geralmente o método de alocação estática, mas existem algumas outras) ou um método de cópia, você também possui a memória e deve liberá-la quando terminar.

Mas se você receber algo de volta de praticamente qualquer outra coisa, incluindo métodos de fábrica (por exemplo [NSString stringWithFormat]), terá uma referência de liberação automática, o que significa que ela poderá ser lançada em algum momento no futuro por outro código - por isso é vital que, se você precisar para mantê-lo além da função imediata que você o retém. Caso contrário, a memória pode permanecer alocada enquanto você a estiver usando ou ser liberada, mas coincidentemente ainda válida, durante o teste do emulador, mas é mais provável que seja liberada e apareça como erros de acesso incorreto ao executar no dispositivo.

A melhor maneira de rastrear essas coisas, e uma boa idéia de qualquer maneira (mesmo que não haja problemas aparentes) é executar o aplicativo na ferramenta Instrumentos, especialmente com a opção Vazamentos.

philsquared
fonte
2
Eu tinha algum código de amostra do acelerômetro que não era vital para o meu aplicativo, que após a remoção eliminou o erro de acesso incorreto. O que faz sentido, considerando que o simulador não possui um acelerômetro. Acho estranho que esse código tenha existido, intocado, por uma semana antes de causar esse erro ...
Héctor Ramos
Como eu sou novo no Objective-C, a maioria dos meus problemas deve surgir do gerenciamento de memória. Depois de alguns anos em C ++, tenho usado principalmente Java nos últimos três ou quatro anos, por isso fiquei enferrujado no gerenciamento de memória. Obrigado pela sua resposta!
Héctor Ramos
4
Não tem problema - feliz que você tenha corrigido. O gerenciamento de memória não é realmente difícil de superar - você só precisa aprender as regras e adotar bons hábitos.
philsquared 30/11/08
O problema que tive parece ser exclusivamente agressivo ao liberar as cordas (e outras) que eu crio. Ainda não tenho 100% de certeza sobre o que deve ser lançado e quando, mas a resposta de Phil certamente ajudou.
257 pluckyglen #
Se eu segui isso corretamente, cmculloh, sim, foi a coisa certa a fazer. Você não possui o objeto return de objectAtIndex.
philsquared 11/09/09
101

Uma das principais causas de EXC_BAD_ACCESS é a tentativa de acessar objetos liberados.

Para descobrir como solucionar isso, leia este documento: DebuggingAutoReleasePool

Mesmo que você não ache que está "liberando objetos liberados automaticamente", isso se aplicará a você.

Este método funciona extremamente bem. Eu uso o tempo todo com grande sucesso !!

Em resumo, isso explica como usar a classe de depuração NSZombie do Cocoa e a ferramenta "malloc_history" da linha de comando para encontrar exatamente qual objeto liberado foi acessado no seu código.

Nota:

A execução de instrumentos e a verificação de vazamentos não ajudarão a solucionar problemas de EXC_BAD_ACCESS. Tenho certeza de que vazamentos de memória não têm nada a ver com EXC_BAD_ACCESS. A definição de vazamento é um objeto ao qual você não tem mais acesso e, portanto, não pode chamá-lo.

ATUALIZAÇÃO: Agora eu uso instrumentos para depurar vazamentos. No Xcode 4.2, escolha Produto-> Perfil e, quando o Instruments for iniciado, escolha "Zombies".

Bentford
fonte
18
Essa nota lateral é muito importante. Vazamentos não podem causar EXC_BAD_ACCESS (eles têm outros problemas). Eu escrevi isso para tentar esclarecer equívocos sobre EXC_BAD_ACCESS loufranco.com/blog/files/Understanding-EXC_BAD_ACCESS.html
Lou Franco
4
Essa ferramenta de zumbis no Xcode é brilhante! Eu encontrei o culpado em 3 minutos, não horas.
Aram Kocharyan
1
o link acima na resposta não está disponível. Mostra erro 404 não encontrado.
Tejas
12

Um sinal EXC_BAD_ACCESS é o resultado da passagem de um ponteiro inválido para uma chamada do sistema. Consegui um hoje cedo com um programa de teste no OS X - eu estava passando uma variável não inicializada pthread_join(), devido a um erro de digitação anterior.

Não estou familiarizado com o desenvolvimento do iPhone, mas verifique todos os ponteiros de buffer que está passando para as chamadas do sistema. Aumente o nível de aviso do seu compilador até o fim (com gcc, use as opções -Walle -Wextra). Habilite o maior número possível de diagnósticos no simulador / depurador.

Adam Rosenfield
fonte
8

Na minha experiência, isso geralmente é causado por um acesso ilegal à memória. Verifique todos os ponteiros, especialmente os de objetos, para garantir que sejam inicializados. Verifique se o arquivo MainWindow.xib, se você estiver usando um, está configurado corretamente, com todas as conexões necessárias.

Se nenhuma dessas verificações no papel exibir alguma coisa e isso não acontecer ao executar uma etapa única, tente localizar o erro com as instruções NSLog (): espalhe seu código com elas, movendo-as até isolar a linha que está causando o erro. Em seguida, defina um ponto de interrupção nessa linha e execute seu programa. Quando você atinge o ponto de interrupção, examine todas as variáveis ​​e os objetos nelas, para ver se algo não parece o esperado. Eu ficaria de olho nas variáveis ​​cuja classe de objeto é algo que você não esperava. Se uma variável deve conter uma UIWindow, mas ela possui uma NSNotification, o mesmo erro de código subjacente pode estar se manifestando de maneira diferente quando o depurador não está em operação.

Brent Royal-Gordon
fonte
7

Passei algumas horas rastreando um EXC_BAD_ACCESS e encontrei o NSZombies e outros ambientes não pareciam me dizer nada.

Para mim, foi uma declaração estúpida do NSLog com especificadores de formato, mas nenhum argumento foi passado.

NSLog(@"Some silly log message %@-%@");

Corrigido por

NSLog(@"Some silly log message %@-%@", someObj1, someObj2);
Scott Heaberlin
fonte
6

Os vídeos da WWDC de 2010 estão disponíveis para todos os participantes do programa de desenvolvedores da apple. Há um ótimo vídeo: "Sessão 311 - Análise avançada de memória com instrumentos", que mostra alguns exemplos de uso de zumbis em instrumentos e depuração de outros problemas de memória.

Para um link para a página de login, clique AQUI .

Jonah
fonte
6

Não é uma resposta completa, mas uma situação específica em que eu recebi isso é ao tentar acessar um objeto que 'morreu' porque tentei usar a liberação automática:

netObjectDefinedInMyHeader = [[[MyNetObject alloc] init] autorelease];

Por exemplo, eu estava passando isso como um objeto para 'notificar' (registrei como ouvinte, observador, qualquer idioma que você quiser), mas ele já havia morrido assim que a notificação foi enviada e eu recebi o EXC_BAD_ACCESS. Alterá-lo para [[MyNetObject alloc] init]e liberá-lo mais tarde, conforme apropriado, resolveu o erro.

Outro motivo para isso acontecer é, por exemplo, se você passar um objeto e tentar armazená-lo:

myObjectDefinedInHeader = aParameterObjectPassedIn;

Mais tarde, ao tentar acessar myObjectDefinedInHeader, você poderá ter problemas. Usando:

myObjectDefinedInHeader = [aParameterObjectPassedIn retain];

pode ser o que você precisa. É claro que esses são apenas alguns exemplos do que eu encontrei e há outras razões, mas elas podem ser ilusórias, então eu as mencionei. Boa sorte!

Roubar
fonte
5

Apenas para adicionar outra situação em que isso pode acontecer:

Eu tinha o código:

NSMutableString *string;
[string   appendWithFormat:@"foo"];

Obviamente eu tinha esquecido de alocar memória para a string:

NSMutableString *string = [[NSMutableString alloc] init];
[string   appendWithFormat:@"foo"];

resolve o problema.

gnuchu
fonte
Isso não causa nenhum erro para mim, porque a string é inicializada como nula e o uso do padrão de objeto nulo chamando um método nil não faz nada.
Liron Yahdav
5

Outro método para capturar exceções EXC_BAD_ACCESS antes que elas ocorram é o analisador estático , no XCode 4+.

Execute o analisador estático com Produto> Analisar (shift + cmd + B). Clicar em qualquer mensagem gerada pelo analisador sobreporá um diagrama em sua fonte, mostrando a sequência de retenções / liberações do objeto incorreto.

insira a descrição da imagem aqui

ericsoco
fonte
5

Acho útil definir um ponto de interrupção em objc_exception_throw. Dessa forma, o depurador deve quebrar quando você obtém o EXC_BAD_ACCESS.

As instruções podem ser encontradas aqui Técnicas de depuração

lyonanderson
fonte
4

Use a regra simples de "se você não a alocou ou reteve, não a solte".

Ponto Gama
fonte
1
Expanda essa regra "... copie-a ..." e você ficará bem.
Até
4

Como depurar EXC_BAD_ACCESS

Confira o link acima e faça o que diz .... Apenas algumas instruções rápidas para usar o NSZombies

Execute o aplicativo e depois que ele falhar (deve exibir "Interrompido" em vez de "EXC_BAD_ACCESS" ... verifique o console (Executar> console)) ... deve haver uma mensagem lá agora informando qual objeto ele estava tentando acessar.

-Ben

Ben Call
fonte
3

Venho depurando e refatorando o código para solucionar esse erro nas últimas quatro horas. Uma postagem acima me levou a ver o problema:

Propriedade anterior: startPoint = [[DataPoint alocado] init]; startPoint = [DataPointList objectAtIndex: 0];
. . . x = startPoint.x - 10; // EXC_BAD_ACCESS

Propriedade após: startPoint = [[DataPoint alocado] init]; startPoint = [[DataPointList objectAtIndex: 0] reter];

Adeus EXC_BAD_ACCESS


fonte
Eu cometi um erro semelhante. Esqueci-me de repetir a instância que causou o travamento e passei horas para descobrir. Sua experiência me iluminou para descobrir a minha. Obrigado!
precisa saber é o seguinte
3

Espero que você esteja liberando a 'corda' quando terminar!


fonte
3

Eu esqueci de retornar a si mesmo em um método init ...;)

denbec
fonte
Esse deve ser um aviso / erro em tempo de compilação e não um EXC_BAD_ACCESS durante o tempo de execução.
stigi 29/07
3

Este é um excelente tópico. Aqui está minha experiência: eu errei com a palavra-chave reter / atribuir em uma declaração de propriedade. Eu disse:

@property (nonatomic, assign) IBOutlet UISegmentedControl *choicesControl;
@property (nonatomic, assign) IBOutlet UISwitch *africaSwitch;
@property (nonatomic, assign) IBOutlet UISwitch *asiaSwitch;

onde eu deveria ter dito

@property (nonatomic, retain) IBOutlet UISegmentedControl *choicesControl;
@property (nonatomic, retain) IBOutlet UISwitch *africaSwitch;
@property (nonatomic, retain) IBOutlet UISwitch *asiaSwitch;
fool4jesus
fonte
1
Estranho, por que você precisaria reter o IBOutlet? O gerenciamento deles é feito para você automaticamente.
jv42
3

Encontrei EXC_BAD_ACCESS no iPhone apenas enquanto tentava executar um método C que incluía uma grande matriz. O simulador conseguiu me fornecer memória suficiente para executar o código, mas não o dispositivo (o array tinha um milhão de caracteres, portanto, era um pouco excessivo!).

O EXC_BAD_ACCESS ocorreu logo após o ponto de entrada do método e me deixou confuso por um bom tempo porque não estava nem perto da declaração da matriz.

Talvez alguém possa se beneficiar das minhas duas horas de puxar o cabelo.

mblackwell8
fonte
3

Esqueceu de tirar um ponteiro não alocado de dealloc. Eu estava obtendo o exc_bad_access no meu rootView de um UINavigationController, mas apenas algumas vezes. Presumi que o problema estava no rootView porque estava travando na metade do seu viewDidAppear {}. Acabou acontecendo apenas depois que eu exibi a visualização com o lançamento ruim do {}, e foi isso!

"EXC_BAD_ACCESS" [Mudando para o processo 330] Nenhuma memória disponível para programar agora: inseguro para chamar malloc

Eu pensei que era um problema onde eu estava tentando alocar ... não onde eu estava tentando liberar um não alocado, D'oh!

Josh
fonte
3

Como lido com EXC_BAD_ACCESS

Às vezes, sinto que, quando um erro EXC_BAD_ACCESS é lançado, o xcode mostrará o erro na classe main.m, não fornecendo informações adicionais sobre o local da falha (às vezes).

Nesses momentos, podemos definir um ponto de interrupção excepcional no Xcode para que, quando a exceção for detectada, um ponto de interrupção seja colocado e intimamente diretamente ao usuário que a falha ocorreu nessa linha

insira a descrição da imagem aqui

iPrabu
fonte
2

Chamadas NSAssert () para validar parâmetros de método é bastante útil para rastrear e evitar passar nils também.

Ryan Townshend
fonte
2

Eu apenas tive esse problema. Para mim, o motivo foi excluir um objeto gerenciado CoreData e tentar lê-lo posteriormente de outro local.

konryd
fonte
2

Venho depurando e refatorando o código para solucionar esse erro nas últimas quatro horas. Uma postagem acima me levou a ver o problema:

Propriedade antes:

startPoint = [[DataPoint alloc] init] ;
startPoint= [DataPointList objectAtIndex: 0];
x = startPoint.x - 10; // EXC_BAD_ACCESS

Propriedade após:

startPoint = [[DataPoint alloc] init] ;
startPoint = [[DataPointList objectAtIndex: 0] retain];

Adeus EXC_BAD_ACCESS

Muito obrigado pela sua resposta. Eu tenho lutado com esse problema o dia todo. Você é incrível!


fonte
4
Você não está substituindo imediatamente o startPoint? Eu não acho que você precise da primeira linha.
toxaq
2
Não há absolutamente nenhuma necessidade de alocar e inicializar uma variável se você a substituir imediatamente por outra. Você está apenas vazando o objeto na primeira tarefa.
dreamlax
2

Apenas para adicionar

O Lynda.com tem um DVD fantástico chamado

Treinamento essencial do iPhone SDK

e o Capítulo 6, Lição 3, trata de EXEC_BAD_ACCESS e de trabalhar com Zombies.

Foi ótimo para mim entender, não apenas o código de erro, mas como posso usar o Zombies para obter mais informações sobre o objeto liberado.

balexandre
fonte
2

Para verificar qual pode ser o erro

Use NSZombieEnabled.

Para ativar o recurso NSZombieEnabled no seu aplicativo:

Escolha Projeto> Editar executável ativo para abrir a janela Informações executáveis. Clique em argumentos. Clique no botão Adicionar (+) na seção "Variáveis ​​a serem definidas no ambiente". Digite NSZombieEnabled na coluna Nome e YES na coluna Valor. Verifique se a marca de seleção da entrada NSZombieEnabled está selecionada.

Encontrei esta resposta no iPhoneSDK

zambono
fonte
2

Sei que isso foi perguntado há algum tempo, mas depois de ler este tópico, encontrei a solução para o XCode 4.2: Produto -> Editar esquema -> Guia Diagnóstico -> Ativar objetos zumbis

Ajudou-me a encontrar uma mensagem sendo enviada para um objeto desalocado.

Sean Aitken
fonte
2

Quando você tem uma recursão infinita, acho que você também pode ter esse erro. Este foi um caso para mim.

coolcool1994
fonte
1

Ainda outra possibilidade: usando blocos em filas, pode facilmente acontecer que você tente acessar um objeto em outra fila, que já foi desalocada no momento. Normalmente, quando você tenta enviar algo para a GUI. Se o ponto de interrupção da exceção estiver sendo definido em um local estranho, talvez seja essa a causa.

raio cerebral
fonte
1

Eu entendi porque eu não estava usando [self performSegueWithIdentifier:sender:]e -(void) prepareForSegue:(UIstoryboardSegue *)certo

DHShah01
fonte
1

Não esqueça o @símbolo ao criar strings, tratando C-stringscomo NSStringscausará EXC_BAD_ACCESS.

Usa isto:

@"Some String"

Em vez disso:

"Some String"

PS - normalmente ao preencher o conteúdo de um arraycom muitos registros.

Artur
fonte