2009-05-27 8 views
10

Tengo una pequeña aplicación que descarga precios de acciones y estaba funcionando perfectamente (durante años) hasta mi reciente actualización a 10.5.7. Después de la actualización, el programa se bloqueará en esta llamada:NSURLConnection estrellarse debajo de 10.5.7

NSString *currinfo = [NSString stringWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://finance.yahoo.com/d/quotes.csv?s=%@&f=l1c1p2", escsymbol]]]; 

Curiosamente, el bloqueo no ocurre de inmediato. Esta línea de código se llama muchas veces, sin problemas, y luego el programa finalmente falla después de 1-2 horas debido a un bloqueo en esta llamada.

Originalmente tenía una publicación larga que describía mis intentos de investigar este problema. Recibí dos sugerencias: (i) hacer que la llamada sea asincrónica (probablemente mejor de todos modos) y (ii) usar NSZombieEnabled para investigar la posibilidad de que un objeto Objective-C sea desasignado anticipadamente (este comentario se realizó en respuesta a los seguimientos de la pila que muestran fallas en objc_msgSend).

Pasé mucho tiempo haciendo la llamada asíncrona (usando [[NSURLConnection alloc] initWithRequest: el delegado de la petición: self]) y esto no ayudó. El programa todavía falló eventualmente, generalmente después de 10-15 minutos. Durante este intervalo antes de la falla, muchas llamadas asincrónicas se realizaron sin ningún problema, se devolvieron los datos, etc. Todo estaba bien. Entonces el programa se bloqueó de repente de nuevo.

Luego encendí NSZombieEnabled. Efectivamente, cuando el programa se estrelló finalmente me dieron el mensaje:

-[CFArray count]: message sent to deallocated instance 0x16b90bd0 

"información malloc 0x16b90bd0" y luego cedido:

0: 0x93db810c in malloc_zone_malloc 
1: 0x946bc3d1 in _CFRuntimeCreateInstance 
2: 0x9464a138 in __CFArrayInit 
3: 0x946cd647 in _CFStreamScheduleWithRunLoop 
4: 0x932d1267 in _Z16_scheduleRStreamPKvPv 
5: 0x946bf15c in CFSetApplyFunction 
6: 0x932b0e2b in CFNSchedulingSetScheduleReadStream 
7: 0x9331a310 in _ZN12HTTPProtocol19createAndOpenStreamEv 
8: 0x9332e877 in _ZN19URLConnectionLoader24loaderScheduleOriginLoadEPK13_CFURLRequest 
9: 0x9332d739 in _ZN19URLConnectionLoader26LoaderConnectionEventQueue33processAllEventsAndConsumePayloadEP20XConnectionEventInfoI12XLoaderEvent18XLoaderEventParamsEl 
10: 0x9332dbdd in _ZN19URLConnectionLoader13processEventsEv 
11: 0x932d8dbf in _ZN17MultiplexerSource7performEv 
12: 0x946ba595 in CFRunLoopRunSpecific 
13: 0x946bac78 in CFRunLoopRunInMode 
14: 0x9058c530 in +[NSURLConnection(NSURLConnectionReallyInternal) _resourceLoadLoop:] 
15: 0x90528e0d in -[NSThread main] 
16: 0x905289b4 in __NSThread__main__ 
17: 0x93de8155 in _pthread_start 
18: 0x93de8012 in thread_start 

no soy un experto en la lectura de seguimientos de pila, pero no lo hace esta traza indicar un problema en el código de Apple, en lugar de mi código? ¿O podría de alguna manera ser responsable de la desasignación del CFArray en cuestión? ¿Hay alguna forma de que investigue más a fondo la causa del problema?


(Aquí está el resto de mi post original)

Al ver que stringWithContentsOfURL es obsoleto, me cambié a este código:

pathURL = [NSURL URLWithString:[NSString stringWithFormat:@"http://finance.yahoo.com/d/quotes.csv?s=%@&f=l1c1p2", escsymbol]]; 

NSURLRequest *request = [NSURLRequest requestWithURL:pathURL cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:30.0]; 

responseData = [ NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error]; 

NSString *currinfo = nil; 

if ([error code]) { dNSLog((@"%@ %d %@ %@ %@", [ error domain], [ error code], [ error localizedDescription], request, @"file://localhost/etc/gettytab")); } 

Esto no ayuda. El programa vuelve a colgarse en la línea sendSynchronousRequest después de una longitud arbitraria de tiempo, con esta información en el depurador:

0 0x93db7286 in mach_msg_trap 
1 0x93dbea7c in mach_msg 
2 0x946ba04e in CFRunLoopRunSpecific 
3 0x946bac78 in CFRunLoopRunInMode 
4 0x932b53eb in CFURLConnectionSendSynchronousRequest 
5 0x905dca4b in +[NSURLConnection sendSynchronousRequest:returningResponse:error:] 

... etc.

El desplome de las propiedades en realidad podría estar en un subproceso diferente:

0 libobjc.A.dylib     0x965c3688 objc_msgSend + 24 
1 com.apple.CoreFoundation  0x946cc581 _CFStreamSignalEventSynch + 193 
2 com.apple.CoreFoundation  0x946ba595 CFRunLoopRunSpecific + 3141 
3 com.apple.CoreFoundation  0x946bac78 CFRunLoopRunInMode + 88 
4 com.apple.Foundation   0x9058c530 +[NSURLConnection(NSURLConnectionReallyInternal) _resourceLoadLoop:] + 320 
5 com.apple.Foundation   0x90528e0d -[NSThread main] + 45 
6 com.apple.Foundation   0x905289b4 __NSThread__main__ + 308 
7 libSystem.B.dylib    0x93de8155 _pthread_start + 321 
8 libSystem.B.dylib    0x93de8012 thread_start + 34 

que supongo que es el subproceso generado para descargar la URL. Por cierto, el código de manejo de errores funciona bien, cuando intencionalmente causo un error desconectándome de internet, el error es reportado en la consola y el programa no se cuelga.

Esto es increíblemente frustrante. Me encantaría dedicar todo el tiempo que sea necesario para rastrear el problema, pero estoy al límite de mis conocimientos con gdb y especialmente con el lenguaje ensamblador. No sé cómo averiguar cuál es el problema real del código de la Fundación. Al principio pensé que tal vez la autorellenada NSString escsymbol está siendo desasignada de algún modo, pero enviarla como retener no ayudó.Si este fuera el caso, ¿cómo podría probarlo?

Hay alguien más tiene este problema?

+0

Por favor, eche un vistazo a esta referencia sobre cómo formatear correctamente sus publicaciones. Use el botón de código al escribir código o pegar el resultado del registro de errores, y use la notación de reducción adecuada para negrita, cursiva, etc. De lo contrario, su publicación no es legible y las personas no responderán su pregunta. Me he encargado de ti esta vez. http://stackoverflow.com/editing-help –

+0

Para su información, esto todavía está sucediendo en 10.6.1, solo a una tasa mucho más reducida (mi prueba lo muestra a una solicitud en miles, en lugar de a 2/100 ya que era en 10.5.7). –

Respuesta

9

Creo que la respuesta de Eugene en este hilo describe correctamente el problema; después de algunas pruebas , aquí está lo que he llegado a la conclusión de que está sucediendo, con suerte algunos detalles para ayudar a otros a atenerse a este problema:

Redirigir las URL causará periódicamente fallas. Esto sucede tanto en la sincronización como en los usos asincrónicos de NSURLConnection. Creé un proyecto de prueba para rastrear este error, y este bloqueo se producirá de forma constante (por lo general, entre 25 y 500 repeticiones). Ejecutar la misma prueba en 10.5.6 o sin redirigir las URL no falla (se han ejecutado hasta 20,000 iteraciones).

Hay dos posibles soluciones temporales:

  1. No utilice redirigir URL:
    Obviamente, esto no siempre es posible, pero si es una URL conocida, puede seguir utilizando las llamadas simples (como stringWithContentsOfURL:) y esto funcionará bien. Dennis, en su caso, la URL del servidor correcto es download.finance.yahoo.com, no finance.yahoo.com, así que creo que esto solucionaría su problema en particular. Usando curl puede ver que obtiene un redireccionamiento 301 cuando toca la última dirección.
  2. Use las llamadas asincrónicas e implemente connection:willSendRequest:redirectResponse:
    Si implementa incluso el manejo más básico de este método delegado, todo parece funcionar. Si omite esta llamada (y deja que el sistema use su implementación predeterminada), obtendrá el bloqueo. Para una implementación básica, simplemente devolver la solicitud que se pasa:
- (NSURLRequest *)connection:(NSURLConnection *)connection 
      willSendRequest:(NSURLRequest *)request 
      redirectResponse:(NSURLResponse *) redirectResponse 
{ 
    return request; 
} 

Todo esto parece sugerir a mí que hay algo roto en la aplicación de Apple en 10.5.7, pero si alguien más tiene ideas sobre lo que podría estar pasando, por favor toque.

He enviado un error con mi proyecto de prueba a Apple como rdar://6936109 y he mencionado el informe de tjw (Radar 6932684).

+0

Guau, Colin, gracias por esto. Desconecté la sugerencia de Eugene porque estaba seguro de que tenía la URL correcta. Sintiéndome bastante tonto ahora. Estoy intentando solucionarlo e informaré lo antes posible. – Dennis

+0

Esto funciona! Gracias sinceramente a todos los que intervinieron. Por curiosidad, alguien sabe si es posible hacer lo que pido más arriba en respuesta a tjw, es decir, simplemente aislar el problema para que un bloqueo en NSURLConnection no elimine todo el programa (a menos de usar un proceso separado)? – Dennis

+0

Colin, ¿estaría dispuesto a compartir su código de muestra para esto (si todavía lo tiene)? Creo que esta es la causa de una caída que están teniendo mis usuarios y me gustaría jugar con ella un poco. Además, ¿estaría dispuesto a publicar su radar en openradar.appspot.com? Me gustaría enviar un radar duplicado para obtener otro dup. ¿Has escuchado algo en este radar? Gracias! – kdbdallas

0

me gustaría sugerir que no utilizan conexiones síncronas URL. Requiere cierta reestructuración de código, pero es un mal comportamiento bloquear el hilo principal en la red. (Suponiendo que estás haciendo esto en el hilo principal).

Además, yo supongo que es código que Apple está planeando menospreciar o dejar de mantener, lo que podría ser lo que estás viendo aquí.

Espero que ayude ....

+0

De hecho, estoy considerando cambiar a una conexión asíncrona. Me preocupa que hacerlo no solucione el problema. Como señala Colin a continuación, la llamada síncrona se basa presumiblemente en el mecanismo asíncrono. Por otro lado, ¡me he quedado sin ideas! – Dennis

+0

Bien, cambié a una conexión asíncrona y no me ayudó. He editado la publicación original para reflejar esta información. – Dennis

0

Estamos viendo el mismo problema, utilizando los stringWithContentsOfURL y sendSynchronousRequest no en desuso (en diferentes lugares). Vemos el mismo tipo de comportamiento; la llamada puede funcionar bien para muchas iteraciones, y luego fallará aleatoriamente (en solicitudes idénticas).

Teniendo en cuenta que las llamadas síncronas se construyen en la parte superior del mecanismo asíncrono, no hay razón para estas llamadas no deben aún estar funcionando correctamente. Desafortunadamente, tampoco tenemos una solución.

+2

Después de tomar mucho tiempo para cambiar al mecanismo asincrónico, he llegado a la conclusión de que la naturaleza síncrona y asincrónica de la llamada no tiene nada que ver con eso. Creo que solo hay un problema en NSURLConnection. Ver mis ediciones a la publicación original anterior. – Dennis

4

Los caídas de objc_msgSend son por lo general debido a su periodo de vigencia objeto inadecuada (es decir, objeto ha sido puesto en libertad y está siendo enviado un mensaje).

ejecutar su código con NSZombieEnabled de averiguar si esto es realmente su problema y para ver qué objeto está siendo puesta en libertad anticipada.

+0

Gracias por esto, diciu, aprendí mucho siguiendo esta sugerencia. – Dennis

2

En The Omni Group, estamos viendo este nuevo bloqueo en 10.5.7 en todas nuestras aplicaciones que usan NSURL también, en uso asincrónico (así que creo que lo sincrónico es una pista falsa). También hemos tenido que suceder en TextMate (presumiblemente en la actualización de software).

He registrado Radar 6932684 sobre este tema, y ​​si también lo está viendo, le recomiendo que lo denuncien, con los detalles que pueda reunir.

+0

Gracias, tjw, repicaré en Apple. – Dennis

+1

OK, así que archivé un informe de error en Apple, que no me llevó a ninguna parte. Aquí está mi nueva pregunta: ¿hay alguna forma de aislar este problema, excepto ejecutarlo como un proceso separado, para que no bloquee todo el programa? En otras palabras, me gustaría dejar que NSURLConnection falle y evitar que mi programa falle.¿Hay algún tipo de bloque "try" que pueda aislarme contra el fracaso de objc_msgSend? – Dennis

5

Esto parece estar relacionado con las redirecciones. Mi aplicación descarga aproximadamente 500 megas de datos directamente (unos cientos de archivos separados) y no se cuelga. La misma aplicación que descarga un conjunto de URL más pequeño, todos los cuales se redirigen, se bloqueará aleatoriamente varias veces exactamente en ese punto (el reinicio se reanudará y el reinicio una y otra vez resultará en una descarga exitosa).

EDIT: Por cierto, no parece la sugerencia de Colin sobre redirecciones reimplementar a trabajar para NSURLDownload :(

Edit2:.. Bueno, esto parece ser una condición de carrera Adición cerr < < "redirigir" < < endl ; en la devolución de llamada "me lo arregla" con NSURLDownload. Dormir durante 1 segundo o bloquear un mutex estático local no tiene ningún efecto ...

+1

Recibí un comentario similar de Jeff Johnson en la lista de cacao-dev. Así que supongo que la única solución confiable por el momento es evitar las redirecciones. Apple necesita entrar en esto. – Dennis

2

También he visto este mismo bloqueo apareciendo en 10.5.7 en varias aplicaciones.

Dado que la implementación del método delegado connection:willSendRequest:redirectResponse: más simple resolverá el problema, creo que podría estar muy relacionado con radar #6700222.

1

Por lo que vale la pena, esto parece ser fijo en 10.5.8 --- pero ha sido reemplazado por un nuevo error que antepone respuesta en el cuerpo de la redirección a la respuesta real de alrededor del 2% de las veces. (Fácil de reproducir girando en -stringWithContentsOfURL :, pero también lo hemos visto en la naturaleza.) Informó ese error como radar # 7169953.

+0

Lo retiro; todavía estamos recibiendo el bloqueo, aunque con menos frecuencia, en 10.5.8. Los símbolos son diferentes, pero se cuelga en una llamada a un puntero NULL dentro de _signalEventSync(), dentro de __cfstream_shared_signalEventSync(), dentro de _CFRunLoopRunSpecific(). En cuanto a CF-476.19/CFStream.c de Apple, hay un comentario que indica que saben sobre el problema (como RADAR 6793636) pero por alguna razón no lo están arreglando. –