Vida útil de los objetos en Java vs .Net
Yo estaba leyendo "CLR a través de C #" y parece que en este ejemplo, el objeto que fue asignado inicialmente a 'obj' será elegible para Garbage Collection después de que la línea 1 se ejecute, no después de la línea 2.
void Foo() { Object obj = new Object(); obj = null; }
Esto se debe a que la vida útil variable local no se define por el ámbito en el que se definió, sino por la última vez que lo lee.
- Android Google Maps v2 no muestra el icono Compass and Location
- Cómo tomar array de json respuesta en java
- ¿Es posible usar VectorDrawable en Botones y TextViews usando android: DrawableRight?
- El controlador no pudo establecer una conexión segura con SQL Server mediante el cifrado de Secure Sockets Layer (SSL)
- Fragmentos en ViewPager son nulos después onresume
Así que mi pregunta es: ¿qué pasa con Java? He escrito este programa para comprobar tal comportamiento, y parece que el objeto permanece vivo. No creo que sea posible que la JVM limite la vida útil variable al interpretar bytecode, así que intenté ejecutar el programa con 'java -Xcomp' para forzar la compilación del método, pero 'finalize' no se llama de todos modos. Parece que no es cierto para Java, pero espero poder obtener una respuesta más precisa aquí. Además, ¿qué hay de la VM de Dalvik para Android?
class TestProgram { public static void main(String[] args) { TestProgram ref = new TestProgram(); System.gc(); } @Override protected void finalize() { System.out.println("finalized"); } }
Añadido: Jeffrey Richter da ejemplo de código en "CLR vía C #", algo así:
public static void Main (string[] args) { var timer = new Timer(TimerCallback, null, 0, 1000); // call every second Console.ReadLine(); } public static void TimerCallback(Object o) { Console.WriteLine("Callback!"); GC.Collect(); }
TimerCallback llamado sólo una vez en MS .Net si el objetivo de los proyectos es 'Release' (temporizador destruido después de la llamada GC.Collect ()), y llamó cada segundo si el objetivo es 'Debug' (aumento de la vida de las variables porque el programador puede intentar acceder al objeto con depurador ). Pero en Mono callback llamado cada segundo no importa cómo lo compila. Parece que la implementación de Timer de Mono hace referencia a la instancia en algún lugar del grupo de subprocesos. La implementación de MS no lo hace.
- Android Video View en otro hilo y problema con android 2.1
- ¿Se considera reflexión y en qué grado?
- Cómo agregar un escucha a un botón de conmutación?
- ¿Qué significa que un método esté obsoleto y cómo puedo resolver los errores resultantes?
- Guardar los datos de acceso (preferencias) android
- eliminar% 0A de la cadena
- Bug z-index ViewPager con PageTransformer no funciona con getChildDrawingOrder
- Receptor de radiodifusión sigue funcionando después de cerrar la aplicación - Android
Tenga en cuenta que sólo porque un objeto puede ser recolectado, no significa que realmente se recogerá un punto determinado – por lo que su método puede dar falsos negativos. Si el método de finalize
cualquier objeto se llama, definitivamente se puede decir que fue inaccesible, pero si el método no se llama, no se puede deducir lógicamente nada. Al igual que con la mayoría de las preguntas relacionadas con el GC, el no determinismo del recolector de basura hace que sea difícil llegar a pruebas / garantías sobre exactamente lo que va a hacer.
En el tema de accesibilidad / recolección, el JLS dice (12.6.1):
Un objeto accesible es cualquier objeto al que se pueda acceder en cualquier cálculo continuo potencial desde cualquier subproceso activo. Las transformaciones de optimización de un programa se pueden diseñar que reducen el número de objetos que son accesibles para ser menos que los que ingenuamente se consideran accesibles. Por ejemplo, un compilador o generador de código puede elegir establecer una variable o parámetro que ya no se utilizará para null para hacer que el almacenamiento de dicho objeto sea potencialmente recuperable antes.
Cuál es más o menos exactamente lo que usted esperaría – pienso que el párrafo antedicho es isomorfo con "un objeto es unreachable si usted definitivamente no lo utilizará más".
Volviendo a su situación original, ¿ puede pensar en alguna ramificación práctica entre el objeto que se considera inalcanzable después de la línea 1 en comparación con la línea 2 ? Mi reacción inicial es que no hay ninguno, y si de alguna manera se las arregló para encontrar una situación así, probablemente sería una marca de código malo / retorcido que causa la VM a la lucha en lugar de una debilidad inherente en el idioma.
Aunque estoy abierto a contra-argumentos.
Edit: Gracias por el interesante ejemplo.
Estoy de acuerdo con su evaluación y ver a dónde va, aunque el problema es probablemente más que el modo de depuración está cambiando sutilmente la semántica de su código.
En el código tal como está escrito, se asigna el Timer
a una variable local que no se lea posteriormente dentro de su ámbito. Incluso el análisis de escape más trivial puede revelar que las variables del timer
no se utilizan en ningún otro lugar en el método main
, y por lo tanto se puede eliminar. Por lo tanto, creo que su primera línea se puede considerar exactamente equivalente a sólo invocar directamente al constructor:
public static void Main (string[] args) { new Timer(TimerCallback, null, 0, 1000); // call every second ...
En este último caso, está claro que el objeto Timer
recién creado no es accesible inmediatamente después de la construcción (suponiendo que no haga nada astuto, como agregarse a los campos estáticos, etc. en su constructor); Y para que se recolectara tan pronto como el GC se diera la vuelta.
Ahora en el caso de depuración las cosas son sutilmente diferentes, por la razón que ha mencionado que es que el desarrollador puede desear inspeccionar el estado de las variables locales más adelante en el método. Por lo tanto, el compilador (y el compilador JIT) no pueden optimizar estos ausentes; Es como si hubiera un acceso de la variable al final del método, evitando la recolección hasta ese punto.
Aún así, no creo que esto cambie realmente la semántica. La naturaleza de GC es que la recolección es raramente garantizada (en Java por lo menos, la única garantía que obtienes es que si se lanzó un OutOfMemoryError entonces todo lo que se consideraba inaccesible se GCed inmediatamente de antemano). De hecho, suponiendo que tuvieras suficiente espacio en la pila para contener todos los objetos creados durante la vida útil del tiempo de ejecución, una implementación de GC sin operaciones es perfectamente válida. Por lo tanto, si bien puede observar cambios de comportamiento en cuántas veces marca el Timer
, esto está bien, ya que no hay garantías sobre lo que verá en función de la forma en que lo esté invocando. (Esto es conceptualmente similar a cómo un temporizador que se ejecuta a lo largo de una tarea de uso intensivo de CPU marcaría más veces cuando el sistema estaba bajo carga – ni el resultado es incorrecto porque la interfaz no proporciona ese tipo de garantía).
En este punto le remito de nuevo a la primera oración en esta respuesta. 🙂
Java, en general, tiene el comportamiento de que si el objeto es accesible en el ámbito (hay una referencia a él que no es basura), entonces el objeto no es basura. Esto es recursivo, por lo que si a
es una referencia a un objeto que tiene una referencia a b
, el objeto b
refiere a no es basura.
Dentro del ámbito en el que todavía se puede llegar al objeto al que hace referencia ref
, (se podría añadir una línea System.out.println(ref.toString())
), ref
no es basura.
Sin embargo, de acuerdo con esta antigua fuente del sitio de Sun , la mayoría depende de la implementación específica de la JVM.
- Cómo crear un borde en un borde de una vista?
- Problema al usar org.apache.commons.net.telnet. * Con android