java - superclase - ¿La referencia al objeto final en el constructor de clase anónimo es una fuga?
superclase java (3)
Estoy pasando un ejecutable a un servicio. La duración ejecutable puede sobrevivir al fragmento / actividad que lo pasa. Me pregunto si el siguiente fragmento de código podría filtrar el objeto frag manteniendo una referencia dentro del ejecutable. Me doy cuenta de que puedo mover toda la línea que contiene frag fuera del ejecutable (como lo hice con "String key = frag ..."), pero estoy pidiendo simplemente para obtener una comprensión de cómo / cuándo una clase anónima se filtraría una objeto.
Realmente no estoy seguro. El ejecutable solo necesita frag para determinar una variable al inicializar la instancia, y se inicializa en línea aquí. Entonces, en teoría, no necesita tener ninguna referencia a frag después de crear la instancia en línea.
Si tuviera una referencia a frag en la función run (), pensaría que una fuga estaría garantizada, ya que necesitaría mantener frag fragmentada para referenciarla en el futuro (y frag podría estar muy bien en ese momento) punto, pero para la referencia).
private static void fg_downloadFile(final FragMyDrive frag, final File file, final Drive drive){
final String key = frag.getCastedActivity().getKey();
Runnable rx_downloadFile = new Runnable() {
Context ServiceContext = frag.getCastedActivity().mService;
@Override
public void run() {
bg_downloadFile(ServiceContext, key, file, drive);
}
};
//.... Submit runnable to service...
}
Como ya sabrá, debe hacer que las variables sean definitivas cuando las declare fuera pero las use en una clase anónima. El truco de Java aquí es copiar todas esas variables en campos de instancia generados implícitamente de esa clase anónima.
Una vez dicho esto, significa que efectivamente hay campos de instancia (en su ejecutable) que contienen copias de todas las variables accedidas del alcance externo. En su ejemplo, también tendría una referencia al FragMyDrive
ya que simplemente está accediendo a él.
Todos esos objetos se vuelven elegibles para la recolección de basura al mismo tiempo que su ejecutable se vuelve elegible para la recolección de basura. Eso significa que la referencia a su FragMyDrive
dentro de su ejecutable mantiene vivo ese objeto mientras esté en ejecución.
Siempre es una buena idea reducir esas referencias a lo que realmente necesita:
private static void fg_downloadFile(final FragMyDrive frag, final File file, final Drive drive){
final String key = frag.getCastedActivity().getKey();
final Context context = frag.getCastedActivity().mService;
Runnable rx_downloadFile = new Runnable() {
@Override
public void run() {
bg_downloadFile(context, key, file, drive);
}
};
//.... Submit runnable to service...
}
Aquí los únicos campos de instancia (generados implícitamente) son:
String key
Context context
File file
Drive drive
Interesante pregunta. ¿Tiene alguna experiencia en programación sin recolección automática de basura, como Objective C?
Pero para responder a su pregunta, no veo por qué sería una filtración. Lo que supongo que sucederá es que Runnable guardará una referencia a frag para su propio uso, pero en algún punto en el futuro, frag también obtendrá basura recolectada una vez que el servicio ya no la necesite y, por lo tanto, no se refiere a eso.
Como la recolección de basura funciona, una vez que un objeto ya no se referencia, estará sujeto a la recolección de basura y desasignado.
No estoy seguro de entender su uso de la palabra en línea correctamente, pero en cualquier caso, no creo que se filtre nada aquí.
Var final String key
es simplemente una referencia local en su función estática fg_downloadFile()
por lo que se libera al salir del ámbito al final de la función.
La clase interna anónima Runnable
aún puede contener una referencia (una vez más, no para frag
sino para alguna propiedad secundaria) mientras dure el hilo Runnable
. (Más precisamente, el compilador en realidad genera una implementation
de Runnable
con un constructor y variables miembro final
que copian las referencias implícitamente usadas a lo que esté disponible en el alcance de fg_downloadFile()
).
Pero en cualquier caso, una vez que se haya ejecutado todo el código, todas las referencias a (sub-miembros de) frag
se eliminarán y el recolector de basura puede recoger la basura.
Espero que esto ayude.