forzar example español como collector java garbage-collection

español - garbage collector java example



¿Cómo evitar que un objeto obtenga basura recolectada? (9)

¿Cómo evitar que un objeto obtenga basura recolectada?

¿Hay algún enfoque por finalización o referencia fantasma o cualquier otro enfoque?

Me hicieron esta pregunta en una entrevista. El entrevistador sugirió que se puede usar finalize() .


Creo que hay un patrón para esto. No estoy seguro si es el patrón de fábrica. Pero tienes un objeto que crea todos tus objetos y contiene una referencia a ellos. Cuando haya terminado con ellos, los quitará de la referencia en la fábrica, haciendo que la llamada sea explícita.


El punto clave es si establecemos que la variable de referencia real apunta al objeto nulo, aunque tenemos variables de instancia de esa clase apuntando a ese objeto no establecido en nulo. El objeto es automáticamente elegible para la recolección de basura. Si guarda el objeto en GC, use este código ...

public class GcTest { public int id; public String name; private static GcTest gcTest=null; @Override protected void finalize() throws Throwable { super.finalize(); System.out.println("In finalize method."); System.out.println("In finalize :ID :"+this.id); System.out.println("In finalize :ID :"+this.name); gcTest=this; } public static void main(String[] args) { GcTest myGcTest=new GcTest(); myGcTest.id=1001; myGcTest.name="Praveen"; myGcTest=null; // requesting Garbage Collector to execute. // internally GC uses Mark and Sweep algorithm to clear heap memory. // gc() is a native method in RunTime class. System.gc(); // or Runtime.getRuntime().gc(); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("/n------- After called GC () ---------/n"); System.out.println("Id :"+gcTest.id); System.out.println("Name :"+gcTest.name); } }

Salida:

En el método de finalización.
En finalizar: ID: 1001
En finalizar: ID: Praveen

------- Después de llamado GC () --------

Id: 1001
Nombre: Praveen


El truco que tu entrevistador estaba buscando probablemente sea que quiere que sepas que puedes evitar que la recolección de basura elimine un objeto forzando una pérdida de memoria.

Obviamente, si mantiene una referencia al objeto en algún contexto de larga duración, no se recopilará, pero eso no es lo que le preguntó el reclutador del OP. Eso no es algo que sucede en el método de finalización.

Lo que puede hacer para evitar la recolección de basura desde el método de finalización es escribir un bucle infinito, en el que se llama a Thread.yield(); (presumiblemente para evitar que un bucle vacío se optimice):

@Override protected void finalize() throws Throwable { while (true) { Thread.yield(); } }

Mi referencia aquí es un artículo de Elliot Back , en el que describe forzar una fuga de memoria por este método.

Solo otra forma en la que finalizar los métodos es malvado .


Esto suena como una de esas preguntas solo para entrevistas, el tiempo lo vas a ver. finalize () se ejecuta cuando su objeto se está recogiendo basura, por lo que sería bastante perverso poner algo allí para evitar la recolección. Normalmente solo tienes una referencia y eso es todo lo que necesitas.

Ni siquiera estoy seguro de qué pasaría si crearas una nueva referencia para algo en el finalizador, ya que el recolector de basura ya decidió recolectarlo, ¿terminarías con una referencia nula? Parece una mala idea, en cualquier caso. p.ej

public class Foo { static Foo reference; ... finalize (){ reference = this; } }

Dudo que esto funcione, o podría funcionar, pero depender de la implementación del GC, o ser un "comportamiento no especificado". Se ve malvado, sin embargo.


La mejor manera es utilizar Unsafe , aunque ByteBuffer podría ser una posible solución para algunos casos.

Busque también la palabra clave "off-heap".

Inseguro

Ventajas sobre ByteBuffer :

  • permite que los objetos se representen directamente, sin serialización y, por lo tanto, más rápido
  • sin límites, tan rápido
  • control explícito de desasignación
  • puede asignar más que el límite de JVM

Sin embargo, no es fácil trabajar. El método se describe en los siguientes artículos:

Todos ellos consisten en los siguientes pasos:

  • necesitamos un operador sizeof , que Unsafe no tiene. Cómo se hizo una pregunta en: En Java, ¿cuál es la mejor forma de determinar el tamaño de un objeto? . Las mejores opciones probablemente sean la API del instrument , pero eso requiere que usted cree un Jar y use opciones especiales de línea de comando ...

  • una vez que tengamos sizeof , asigne suficiente memoria con Unsafe#allocateMemory , que es básicamente un malloc y devuelve una dirección

  • cree un objeto heap en forma regular, cópielo en la memoria asignada con Unsafe#copyMemory . Para hacer esto, necesita la dirección del objeto on-heap y el tamaño del objeto

  • establece un Object para que apunte a la memoria asignada, luego envía el Object a tu clase.

    No parece posible establecer la dirección de una variable directamente con inseguro, por lo que debemos envolver el objeto en una matriz o un objeto contenedor, y usar Unsafe#arrayBaseOffset o Unsafe#objectFieldOffset .

  • Una vez que haya terminado, libere la memoria asignada con freeMemory

Si alguna vez obtengo esto para no segfault, publicaré un ejemplo :-)

ByteBuffer

Ventajas sobre inseguro:

  • estable en las versiones de Java mientras que Unsafe puede romperse
  • realiza la comprobación consolidada, por lo que es más seguro que ... Inseguro, lo que permite fugas de memoria y SIGSEGV

JLS dice :

El contenido de los almacenamientos intermedios directos puede residir fuera del montón recogido de basura normal.

Ejemplo de uso con primitivas:

ByteBuffer bb = ByteBuffer.allocateDirect(8); bb.putInt(0, 1); bb.putInt(4, 2); assert bb.getInt(0) == 1; assert bb.getInt(4) == 2; // Bound chekcs are done. boolean fail = false; try { bb.getInt(8); } catch(IndexOutOfBoundsException e) { fail = true; } assert fail;

Temas relacionados:


Mantenga una referencia. Si su objeto se está recolectando prematuramente, es un síntoma de que tiene un error en el diseño de su aplicación.

El recolector de basura solo recoge objetos a los que no hay referencia en su aplicación. Si no hay ningún objeto que haga referencia de forma natural al objeto recogido, pregúntese por qué debe mantenerse con vida.

Un uso en el que normalmente no tiene referencias, pero desea mantener un objeto es un singleton. En este caso, puede usar una variable estática. Una posible implementación de un singleton se vería así:

public class Singleton { private static Singleton uniqueInstance; private Singleton() { } public static synchronized Singleton getInstance() { if (uniqueInstance == null) { uniqueInstance = new Singleton(); } return uniqInstance; } }

Editar: Técnicamente, puede almacenar una referencia en algún lugar de su finalizador. Esto evitará que el objeto se recopile hasta que el recopilador determine nuevamente que no hay más referencias. Sin embargo, el finalizador solo se llamará una vez como máximo, por lo que debe asegurarse de que su objeto (incluidas sus superclases) no se finalice después de la primera recopilación. Sin embargo, le aconsejo que no use esta técnica en programas reales. (¡Dejará colegas como yo gritando WTF !?;)

protected void finalize() throws Throwable { MyObjectStore.getInstance().store(this); super.finalize(); // questionable, but you should ensure calling it somewhere. }


Me pregunto si lo que están buscando es el patrón con grupos de recursos (por ejemplo, para conexiones de red / db o subprocesos) donde se utiliza finalizar para devolver un recurso al grupo para que el objeto real que contiene el recurso no sea GC '' ed.

Estúpido ejemplo, en pseudocódigo tipo Java y sin ningún tipo de sincronización:

class SlowResourceInternal { private final SlowResourcePool parent; <some instance data> returnToPool() { parent.add(this); } } class SlowResourceHolder { private final SlowResourceInternal impl; <delegate actual stuff to the internal object> finalize() { if (impl != null) impl.returnToPool(); } }


Si todavía hay una referencia al objeto, no se recogerá la basura. Si no hay ninguna referencia a eso, no debería importarle.

En otras palabras, el recolector de basura solo recoge basura. Deja que haga su trabajo.


Sospecho que a lo que se puede estar refiriendo es si su método de finalize esconde una referencia al objeto que se está finalizando. En este caso (si mi lectura de Java Language Spec es correcta), el método de finalize nunca volverá a ejecutarse, pero el objeto aún no será recolectado.

Este no es el tipo de cosas que uno hace en la vida real, ¡excepto posiblemente por accidente!