2011-03-01 23 views
26

Estaba asumiendo que LinkedList.Clear() era O (1) en un proyecto en el que estoy trabajando, ya que utilicé una LinkedList para drenar un BlockingQueue en mi consumidor que necesita un alto rendimiento, borrando y reutilizando LinkedList después.¿Por qué no está LinkedList.Clear() O (1)

Resulta que esa suposición era errónea, ya que el (OpenJDK) código hace esto:

Entry<E> e = header.next; 
    while (e != header) { 
     Entry<E> next = e.next; 
     e.next = e.previous = null; 
     e.element = null; 
     e = next; 
    } 

Este fue un poco sorprendente, ¿hay alguna buena razón LinkedList.Clear no podía simplemente "olvidar" su cabecera .next y header.previous miembro?

+1

http://www.docjar.com/html/api/java/util/LinkedList.java.html Harmony lo tiene O (1) – Bozho

+1

Buena explicación que puede encontrar aquí: http://stackoverflow.com/questions/575995/clear-impl-in-javas-linkedlist. Respondido por Jason – smas

Respuesta

31

El código fuente de la versión que estoy viendo (build 1.7.0-EA-B84) en Eclipse tiene este comentario por encima de ellos:

// Clearing all of the links between nodes is "unnecessary", but: 
// - helps a generational GC if the discarded nodes inhabit 
// more than one generation 
// - is sure to free memory even if there is a reachable Iterator 

Eso hace que sea razonablemente claro por qué están haciendo aunque acepto que es un poco alarmante que convierte una operación O (1) en O (n).

+0

Ok, gracias - esos comentarios no estaban en las fuentes 1.6 :-) – Leri

+2

Solo espero que todos los nodos estén en las páginas que están en la RAM, de lo contrario ... –

+0

La única solución que veo para ese problema sería ampliar la clase con un método claro personalizado. No es tan difícil hacerlo bien (puedes echar un vistazo a la implementación original después de todo y simplemente eliminar la iteración), pero todavía no es algo que me gustaría hacer. Mal diseño de API. – Voo

0

Parece que no puedo comentar las respuestas (?): Los punteros entre el siguiente y el anterior no importan. Dado que no se podrá acceder a ninguna de las entradas internas desde ninguna raíz de GC, se recopilará toda la estructura. Si Java hubiera usado un recopilador de recuento, estaríamos atascados con el problema del ciclo.

Las respuestas correctas son las que John Skeet señala.

3

aunque no estoy muy impresionado con el motivo de la optimización de GC - se vuelve en contra claramente en su caso -

compensación y reutilizar el ListaEnlazada

que no suena bien. ¿por qué no simplemente crear un nuevo objeto LinkedList?

+0

Una referencia existente a uno de los nodos de Entrada parcialmente a través de la lista anterior continuará para ver la lista anterior, y continuará pudiendo iterar a través de ella. (Esto está relacionado con la segunda parte del comentario, y no tiene nada que ver con GC.) – Oddthinking

+0

claramente op no tiene otra referencia en la lista. – irreputable

+0

Tienes razón en que la creación de una nueva LinkedList aquí simplemente eliminaría todo el problema. Al final, cambié a ArrayList, whlle clear() hay O (N), aún lo medimos para un mejor rendimiento, para nuestro caso específico, recolección de basura nuestra lista de enlaces producida entre 150-200 Mb/s de basura solo desde los nodos internos de la lista enlazada (Normalmente no nos interesarían cosas como esa, pero para esta aplicación en particular tenemos que) – Leri

Cuestiones relacionadas