validar recolector programacion ejemplo contpaqi basura java null garbage-collection

recolector - ¿La asignación de objetos a null en Java impacta en la recolección de basura?



recolector de basura programacion (13)

¿La asignación de una referencia de objeto no utilizado a null en Java mejora el proceso de recolección de basura de forma mensurable?

Mi experiencia con Java (y C #) me ha enseñado que a menudo es contra intuitivo intentar y ser más astuto que la máquina virtual o el compilador JIT, pero he visto compañeros de trabajo usar este método y tengo curiosidad si esta es una buena práctica para elegir arriba o una de esas supersticiones de programación vudú?


" Depende "

No sé sobre Java, pero en .net (C #, VB.net ...) generalmente no es necesario asignar un nulo cuando ya no necesita un objeto.

Sin embargo, tenga en cuenta que "generalmente no es necesario".

Al analizar su código, el compilador .net hace una buena valoración del tiempo de vida de la variable ... para saber con precisión cuándo el objeto ya no se usa. Por lo tanto, si escribe obj = null, podría parecer que todavía se está utilizando el obj ... en este caso es contraproducente asignar un nulo.

Hay algunos casos en los que podría ayudar asignar un nulo. Un ejemplo es que tiene un código enorme que se ejecuta durante mucho tiempo o un método que se ejecuta en un subproceso diferente o en algún bucle. En tales casos, puede ser útil asignar un valor nulo para que el GC pueda saber fácilmente que ya no se usa.

No hay una regla dura y rápida para esto. Pasando por el lugar anterior asigna nulos en tu código y ejecuta un generador de perfiles para ver si ayuda de alguna manera. Probablemente no veas un beneficio.

Si está tratando de optimizar el código .net, entonces mi experiencia ha sido que tener mucho cuidado con los métodos Dispose y Finalize es en realidad más beneficioso que preocuparse por los null.

Algunas referencias sobre el tema:

http://blogs.msdn.com/csharpfaq/archive/2004/03/26/97229.aspx

http://weblogs.asp.net/pwilson/archive/2004/02/20/77422.aspx


Al menos en Java, no es programación vudú en absoluto. Cuando creas un objeto en Java usando algo como

Foo bar = new Foo();

haces dos cosas: primero, creas una referencia a un objeto y, en segundo lugar, creas el objeto Foo mismo. Mientras exista esa referencia u otra, el objeto específico no puede ser copiado. sin embargo, cuando asigna null a esa referencia ...

bar = null ;

y suponiendo que nada más tenga una referencia al objeto, se libera y está disponible para gc la próxima vez que pase el recolector de basura.


Depende.

En términos generales, es más corto; mantiene referencias a sus objetos, más rápido será recogido.

Si su método tarda 2 segundos en ejecutarse y ya no necesita un objeto después de un segundo de ejecución del método, tiene sentido borrar cualquier referencia al mismo. Si GC ve que después de un segundo, su objeto todavía está referenciado, la próxima vez podría comprobarlo en un minuto más o menos.

De todos modos, establecer todas las referencias a nulo por defecto es para mí una optimización prematura y nadie debería hacerlo a menos que sea en casos raros específicos en los que se reduzca sensiblemente el consumo de memoria.


En la futura ejecución de su programa, los valores de algunos miembros de datos se usarán para computar una salida visible externa al programa. Otros pueden o no ser utilizados, dependiendo de las entradas futuras (e imposibles de predecir) al programa. Se puede garantizar que otros miembros de datos no se usen. Todos los recursos, incluida la memoria, asignados a esos datos no utilizados se desperdician. El trabajo del recolector de basura (GC) es eliminar esa memoria desperdiciada. Sería desastroso para el GC eliminar algo que era necesario, por lo que el algoritmo utilizado podría ser conservador, conservando más que el mínimo estricto. Podría usar optimizaciones heurísticas para mejorar su velocidad, a cambio de retener algunos elementos que realmente no son necesarios. Hay muchos algoritmos potenciales que el GC podría usar. Por lo tanto, es posible que los cambios que realice en su programa y que no afecten a la corrección de su programa, afecten la operación del GC, ya sea haciendo que funcione más rápido para hacer el mismo trabajo o para identificar antes los elementos no utilizados. Entonces, este tipo de cambio, al establecer una referencia de objeto no utilizado como null , en teoría no siempre es vudú.

¿Es vudú? Según se informa, hay partes del código de la biblioteca Java que hacen esto. Los redactores de ese código son mucho mejores que los programadores promedio y conocen o cooperan con los programadores que conocen los detalles de las implementaciones del recolector de basura. Entonces eso sugiere que a veces hay un beneficio.


En mi experiencia, la mayoría de las veces las personas anulan las referencias por paranoia, no por necesidad. Aquí hay una guía rápida:

  1. Si el objeto A hace referencia al objeto B y ya no necesita esta referencia y el objeto A no es elegible para la recolección de basura, entonces debe anular el campo explícitamente. No es necesario anular un campo si el objeto adjunto está recibiendo basura de todos modos. Anular campos en un método dispose () es casi siempre inútil.

  2. No es necesario anular las referencias de objetos creadas en un método. Se borrarán automáticamente una vez que el método finalice. La excepción a esta regla es si está ejecutando un método muy largo o un ciclo masivo y debe asegurarse de que algunas referencias se borren antes de que finalice el método. De nuevo, estos casos son extremadamente raros.

Diría que la gran mayoría de las veces no tendrá que anular las referencias. Tratar de ser más listo que el recolector de basura es inútil. Acabará con un código ineficiente e ilegible.


Estaba trabajando en una aplicación de videoconferencia una vez y noté una gran diferencia enorme en el rendimiento cuando me tomé el tiempo para hacer referencias nulas tan pronto como ya no necesité el objeto. Esto fue en 2003-2004 y solo puedo imaginar que el GC se haya vuelto aún más inteligente desde entonces. En mi caso, tenía cientos de objetos que entraban y salían fuera del alcance cada segundo, así que noté el GC cuando se iniciaba periódicamente. Sin embargo, después de hacer un punto para anular objetos, el GC dejó de pausar mi aplicación.

Entonces depende de lo que hagas ...


Establecer explícitamente una referencia a null en lugar de simplemente dejar que la variable salga del alcance, no ayuda al recolector de elementos no utilizados, a menos que el objeto sea muy grande, y establecer una nulidad tan pronto como haya terminado es una buena idea.

Generalmente establecer referencias a nulo significa para el LECTOR del código que este objeto está completamente hecho y no debería preocuparse más.

Se puede lograr un efecto similar con la colocación de un juego adicional de llaves

{ int l; { String bigThing = ....; l = bigThing.length(); } --- }

esto permite que bigThing sea basura recolectada justo después de dejar los apoyos anidados.


Incluso si anular la referencia fuera marginalmente más eficiente, ¿valdría la fealdad de tener que acribillar su código con estas feas nulificaciones? Solo serían desordenados y oscurecerían el código de intención que los contiene.

Es una base de código rara que no tiene mejor candidato para la optimización que tratar de ser más listo que el recolector de basura (aún más raro son los desarrolladores que logran superarlo). Lo más probable es que tus esfuerzos se gasten mejor en otro lugar, abandonando ese analizador de Xml crujiente o encontrando alguna oportunidad para almacenar el cómputo en caché. Estas optimizaciones serán más fáciles de cuantificar y no requieren que ensucie su base de código con ruido.


Sí.

De "The Pragmatic Programmer" p.292:

Al establecer una referencia a NULL, se reduce el número de punteros al objeto en uno ... (lo que permitirá que el recolector de basura lo elimine)


Supongo que el OP se refiere a cosas como esta:

private void Blah() { MyObj a; MyObj b; try { a = new MyObj(); b = new MyObj; // do real work } finally { a = null; b = null; } }

En este caso, ¿el VM no los marcaría para GC tan pronto como dejen el alcance de todos modos?

¿O, desde otra perspectiva, establecer explícitamente los artículos en nulo hará que obtengan GC''d antes que lo harían si simplemente salieran del alcance? Si es así, la máquina virtual puede gastar tiempo de GCing el objeto cuando la memoria no se necesita de todos modos, lo que en realidad podría empeorar el rendimiento del uso de la CPU, ya que estaría haciendo GC más temprano.


Típicamente, no.

Pero como todas las cosas: depende. El GC en Java en estos días es MUY bueno y todo debería ser limpiado poco después de que ya no sea alcanzable. Esto es justo después de dejar un método para las variables locales, y cuando ya no se hace referencia a una instancia de clase para los campos.

Solo necesita anular explícitamente si sabe que seguiría siendo referenciado de otra manera. Por ejemplo, una matriz que se mantiene alrededor. Es posible que desee anular los elementos individuales de la matriz cuando ya no los necesite.

Por ejemplo, este código de ArrayList:

public E remove(int index) { RangeCheck(index); modCount++; E oldValue = (E) elementData[index]; int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // Let gc do its work return oldValue; }

Además, anular explícitamente un objeto no hará que un objeto se recopile antes de que salga del alcance de manera natural, siempre y cuando no queden referencias.

Ambos:

void foo() { Object o = new Object(); /// do stuff with o }

y:

void foo() { Object o = new Object(); /// do stuff with o o = null; }

Son funcionalmente equivalentes.


Un buen artículo es el horror codificador de hoy.

La forma en que el trabajo de GC es buscando objetos que no tienen ningún indicador para ellos, el área de su búsqueda es montón / pila y cualquier otro espacio que tengan. Por lo tanto, si establece una variable en nulo, el objeto real ahora no está apuntado por nadie, y por lo tanto podría ser GC''d.

Pero dado que el GC podría no funcionar en ese preciso instante, es posible que en realidad no te compres nada. Pero si su método es bastante largo (en términos de tiempo de ejecución) podría valer la pena, ya que aumentará las posibilidades de que GC recolecte ese objeto.

El problema también puede complicarse con las optimizaciones de código, si nunca usa la variable después de establecerla como nula, sería una optimización segura eliminar la línea que establece el valor en nulo (una instrucción menos para ejecutar). Por lo tanto, es posible que no obtenga ninguna mejora.

Entonces, en resumen, sí puede ayudar, pero no será determinista .


public class JavaMemory { private final int dataSize = (int) (Runtime.getRuntime().maxMemory() * 0.6); public void f() { { byte[] data = new byte[dataSize]; //data = null; } byte[] data2 = new byte[dataSize]; } public static void main(String[] args) { JavaMemory jmp = new JavaMemory(); jmp.f(); } }

El programa anterior arroja OutOfMemoryError . Si descomenta data = null; , OutOfMemoryError está resuelto. Siempre es una buena práctica establecer la variable no utilizada en nulo