Carpeta que evita la recolección de basura

Creo que rastreé una fuga de memoria y quiero confirmar lo que pienso que puede ser cierto acerca de cómo se implementa Binder de Android. En este caso tengo un Servicio y una Actividad, cada uno en su propio proceso. He creado un AIDL que me permite pasar un objeto de devolución de llamada de la actividad al servicio a través de un método ipc y luego tener la devolución de llamada llamada cuando el servicio se realiza con la tarea solicitada.

Durante mucho tiempo me pregunto: si paso un nuevo objeto de devolución de llamada al servicio y no guardo un puntero al objeto de devolución de llamada en mi actividad, ¿por qué el recolector de basura simplemente no tiene que recoger la devolución de llamada en mi actividad ¿proceso? Dado que eso no parece suceder, ¿cómo sabe JVM cuándo recoger basura la devolución de llamada en mi actividad.

Creo que la respuesta es que el sistema Binder mantiene un puntero a mi retorno de llamada en el proceso de actividad hasta que el objeto de devolución de llamada correspondiente en el proceso de servicio tiene su método finalize () llamado, que envía un mensaje a la actividad para liberar el puntero. ¿Es esto correcto? Si no, ¿cómo funciona?

Creo que lo es y conduce a una situación interesante en la que si la devolución de llamada en la actividad apunta a algo muy intensivo en memoria, no se recopilará hasta que se recopile la devolución de llamada en el servicio. Si el servicio no tiene poca memoria, es posible que no recupere la devolución de llamada durante mucho tiempo y que las devoluciones de llamada sólo se acumulen en la actividad hasta que haya un error OutOfMemoryError en la actividad.

Yury es bastante correcto.

Mi servicio inicia un subproceso que contiene la devolución de llamada y cuando el subproceso se realiza con su trabajo llama a la devolución de llamada y el subproceso termina. Cuando se llama la devolución de llamada puede hacer un poco de trabajo en mi actividad y luego volver en qué punto no tengo punteros en mi proceso de actividad a la devolución de llamada.

Sin embargo, el objeto de devolución de llamada en la actividad seguirá siendo señalado por el sistema de encuadernación de Android hasta que el objeto de devolución de llamada correspondiente en el servicio se recoja de basura.

Si el objeto de devolución de llamada en el proceso Actividad domina algunos otros objetos que consumen mucha memoria, entonces estoy desperdiciando memoria en mi proceso de actividad sin ninguna buena razón e incluso podría obtener un OutOfMemoryError. La solución es crear un método sencillo en mi clase de devolución de llamada llamada destory() para destory() todos los campos de la devolución de llamada y llamar a ese método cuando haya terminado con la devolución de llamada.

Si la clase de devolución de llamada es una clase interna no estática, puede considerar cambiarla a una clase interna estática y pasar la clase padre en el constructor, de esta manera puede destory() también en el método destory() .

Esto trae un pensamiento interesante, si la clase padre de una clase de devolución de llamada interna no estática es una actividad y se produce un cambio de configuración (como una rotación de pantalla) después de que la devolución de llamada se envía a través del cuaderno pero antes de que se devuelva La devolución de llamada apuntará a un objeto de actividad antiguo cuando se ejecute!

Actualización : He descubierto este código dentro de Binder.java, por supuesto que está deshabilitado, pero habría sido agradable si mencionaron este tipo de cosas en el Javadocs.

  if (FIND_POTENTIAL_LEAKS) { final Class<? extends Binder> klass = getClass(); if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && (klass.getModifiers() & Modifier.STATIC) == 0) { Log.w(TAG, "The following Binder class should be static or leaks might occur: " + klass.getCanonicalName()); } } 

Si entiendo correctamente cómo Binder trabaja el problema en su caso es el siguiente. Para cada llamada entrante entrante su servicio crea un hilo separado. Cuando pasa un objeto a este subproceso, su sistema Binder crea una copia local de su objeto para el subproceso. Por lo tanto, hasta que su método de servicio ha devuelto el resultado el hilo con la copia del objeto continúa funcionando.

Para comprobar esto, intenta ver los subprocesos de tu proceso de servicio (en DDMS).

FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.