tutorial - datatables change search label




¿Debo desechar() DataSet y DataTable? (7)

¿Creas los DataTables tú mismo? Debido a que iterar a través de los elementos secundarios de cualquier Objeto (como en DataSet.Tables) generalmente no es necesario, ya que es el trabajo de los padres deshacerse de todos sus miembros secundarios.

En general, la regla es: si la creó e implementa IDisposable, elimínela. Si NO lo creó, entonces NO lo elimine, ese es el trabajo del objeto principal. Pero cada objeto puede tener reglas especiales, consulte la Documentación.

Para .net 3.5, dice explícitamente "Deséchelo cuando no lo use más", así que eso es lo que haría.

DataSet y DataTable implementan IDisposable, por lo que, según las mejores prácticas convencionales, debería llamar a sus métodos Dispose ().

Sin embargo, por lo que he leído hasta ahora, DataSet y DataTable en realidad no tienen ningún recurso no administrado, por lo que Dispose () en realidad no hace mucho.

Además, no puedo usar el using(DataSet myDataSet...) porque DataSet tiene una colección de DataTables.

Entonces, para estar seguro, necesitaría iterar a través de myDataSet.Tables, desechar cada una de las tablas de datos y luego deshacerme del DataSet.

Entonces, ¿vale la pena llamar a Dispose () en todos mis DataSets y DataTables?

Apéndice:

Para aquellos de ustedes que piensan que DataSet debería eliminarse: en general, el patrón para deshacerse es usar using o try..finally , porque quiere garantizar que se llamará Dispose ().

Sin embargo, esto se pone muy rápido para una colección. Por ejemplo, ¿qué haces si una de las llamadas a Dispose () arroja una excepción? ¿Se lo traga (que es "malo") para que pueda continuar y disponer el siguiente elemento?

¿O sugieres que acabo de llamar a myDataSet.Dispose () y olvidarme de tirar los DataTables en myDataSet.Tables?


Antes que nada, verificaría qué hace Dispose con un DataSet. Tal vez usar el reflector de Redgate ayudará.


Debes asumir que hace algo útil y llamar a Dispose incluso si no hace nada en el actual. Encarnaciones de NET Framework, no hay garantía de que seguirá siendo así en futuras versiones que conduzcan a un uso ineficiente de los recursos.


Incluso si el objeto no tiene recursos no administrados, la eliminación podría ayudar a GC al romper gráficos de objetos. En general, si el objeto implementa IDisposable, debe llamarse a Dispose ().

Si Dispose () realmente hace algo o no depende de la clase dada. En el caso de DataSet, la implementación de Dispose () se hereda de MarshalByValueComponent. Se elimina del contenedor y llama al evento Disposed. El código fuente está debajo (desmontado con .NET Reflector):

protected virtual void Dispose(bool disposing)
{
    if (disposing)
    {
        lock (this)
        {
            if ((this.site != null) && (this.site.Container != null))
            {
                this.site.Container.Remove(this);
            }
            if (this.events != null)
            {
                EventHandler handler = (EventHandler) this.events[EventDisposed];
                if (handler != null)
                {
                    handler(this, EventArgs.Empty);
                }
            }
        }
    }
}

Llamo a disponer cada vez que un objeto implemente ID. Está ahí por una razón.

Los DataSets pueden ser enormes cerdos de memoria. Cuanto antes puedan marcarse para la limpieza, mejor.

actualizar

Han pasado 5 años desde que respondí esta pregunta. Todavía estoy de acuerdo con mi respuesta. Si hay un método de eliminación, debe invocarse cuando haya terminado con el objeto. La interfaz IDispose se implementó por una razón.


Los conjuntos de datos implementan IDisposable a fondo MarshalByValueComponent, que implementa IDisposable. Dado que los conjuntos de datos se administran, no existe un beneficio real para la disposición de llamadas.


Actualización (1 de diciembre de 2009):

Me gustaría enmendar esta respuesta y admitir que la respuesta original fue defectuosa.

El análisis original sí se aplica a los objetos que requieren finalización, y aún se mantiene el punto de que las prácticas no deberían aceptarse en la superficie sin una comprensión precisa y profunda.

Sin embargo, resulta que los DataSets, DataViews, DataTables suprimen la finalización en sus constructores ; esta es la razón por la cual llamar a Dispose () en ellos explícitamente no hace nada.

Presumiblemente, esto sucede porque no tienen recursos no administrados; por lo tanto, a pesar del hecho de que MarshalByValueComponent tiene en cuenta los recursos no administrados, estas implementaciones particulares no tienen la necesidad y, por lo tanto, pueden omitir la finalización.

(Que los autores de .NET se ocuparían de suprimir la finalización en los mismos tipos que normalmente ocupan más memoria habla de la importancia de esta práctica en general para los tipos finalizables).

No obstante, estos detalles aún no están documentados desde el inicio de .NET Framework (hace casi 8 años) es bastante sorprendente (que esencialmente se los deja en sus propios dispositivos para filtrar el material conflictivo y ambiguo para juntar las piezas). es frustrante a veces, pero proporciona una comprensión más completa del marco en el que confiamos todos los días).

Después de leer un montón, aquí está mi entendimiento:

Si un objeto requiere finalización, podría ocupar la memoria por más tiempo de lo necesario: aquí se explica por qué: a) Cualquier tipo que define un destructor (o hereda de un tipo que define un destructor) se considera finalizable; b) En la asignación (antes de que el constructor se ejecute), se coloca un puntero en la cola de finalización; c) Un objeto finalizable normalmente requiere 2 colecciones para reclamar (en lugar del estándar 1); d) Suprimir la finalización no elimina un objeto de la cola de finalización (según lo informado por! FinalizeQueue en SOS) Este comando es engañoso; Saber qué objetos están en la cola de finalización (en sí mismo) no es útil; Saber qué objetos están en la cola de finalización y todavía requieren finalización sería útil (¿hay un comando para esto?)

La supresión de la finalización se desactiva un poco en el encabezado del objeto, lo que indica al tiempo de ejecución que no necesita tener invocado su Finalizador (no es necesario mover la cola FReachable); Permanece en la cola de finalización (y continúa siendo reportado por! FinalizeQueue en SOS)

Las clases DataTable, DataSet, DataView están enraizadas en MarshalByValueComponent, un objeto finalizable que puede (potencialmente) manejar recursos no administrados.

  • Dado que DataTable, DataSet, DataView no introducen recursos no administrados, suprimen la finalización en sus constructores
  • Si bien este es un patrón inusual, libera a la persona que llama de tener que preocuparse por llamar a Dispose después de su uso.
  • Esto y el hecho de que los DataTables puedan ser potencialmente compartidos en diferentes DataSets, es probable por qué a los DataSets no les importa disponer de DataTables hijo.
  • Esto también significa que estos objetos aparecerán debajo de! FinalizeQueue en SOS
  • Sin embargo, estos objetos aún deberían recuperarse después de una sola colección, como sus contrapartes no finalizables

4 (nuevas referencias):

Respuesta Original:

Hay muchas respuestas engañosas y generalmente muy malas sobre esto: cualquiera que haya aterrizado aquí debe ignorar el ruido y leer las referencias a continuación con cuidado.

Sin duda, debe invocarse a Dispose en cualquier objeto finalizable.

Las tablas de datos son finalizables.

Calling Dispose agiliza significativamente la recuperación de memoria.

MarshalByValueComponent llama a GC.SuppressFinalize (esto) en su Dispose (); omitir esto significa tener que esperar docenas o cientos de colecciones Gen0 antes de reclamar la memoria:

Con esta comprensión básica de la finalización, ya podemos deducir algunas cosas muy importantes:

Primero, los objetos que necesitan finalización viven más tiempo que los objetos que no. De hecho, pueden vivir mucho más tiempo. Por ejemplo, supongamos que un objeto que está en gen2 necesita ser finalizado. La finalización se programará pero el objeto aún está en gen2, por lo que no se volverá a recopilar hasta que suceda la siguiente colección gen2. Eso podría ser un tiempo muy largo y, de hecho, si las cosas van bien, llevará mucho tiempo, porque las colecciones gen2 son costosas y, por lo tanto, queremos que sucedan con muy poca frecuencia. Los objetos más antiguos que necesitan finalización pueden tener que esperar docenas o cientos de colecciones gen0 antes de recuperar su espacio.

Segundo, los objetos que necesitan finalización causan daño colateral. Como los punteros internos del objeto deben seguir siendo válidos, no solo los objetos que necesitan directamente la finalización permanecen en la memoria, sino que todo lo que el objeto se refiere, directa e indirectamente, también permanecerá en la memoria. Si un gran árbol de objetos estuviera anclado por un solo objeto que requiriera finalización, entonces todo el árbol se demoraría, potencialmente por un largo tiempo como acabamos de discutir. Por lo tanto, es importante utilizar los finalizadores con moderación y colocarlos en objetos que tengan la menor cantidad posible de punteros de objeto internos. En el ejemplo de árbol que acabo de dar, puede evitar fácilmente el problema moviendo los recursos que necesitan finalización a un objeto separado y manteniendo una referencia a ese objeto en la raíz del árbol. Con ese modesto cambio, solo un objeto (con suerte, un objeto pequeño y agradable) se quedaría y el costo de finalización se minimizaría.

Finalmente, los objetos que necesitan finalización crean trabajo para el hilo del finalizador. Si el proceso de finalización es complejo, el hilo del finalizador único pasará mucho tiempo realizando esos pasos, lo que puede ocasionar un retraso en el trabajo y, por lo tanto, causar que más objetos permanezcan en espera de la finalización. Por lo tanto, es de vital importancia que los finalizadores hagan el menor trabajo posible. Recuerde también que, aunque todos los punteros de los objetos siguen siendo válidos durante la finalización, es posible que esos punteros conduzcan a objetos que ya se han finalizado y que, por lo tanto, pueden ser menos útiles. En general, es más seguro evitar seguir los punteros de objeto en el código de finalización aunque los punteros sean válidos. Una ruta de código de finalización segura y corta es la mejor.

Tómelo de alguien que haya visto cientos de MB de DataTables no referenciadas en Gen2: esto es muy importante y las respuestas en este hilo no lo recuerdan por completo.

Referencias

1 - 1

2 - 2 http://www.dotnetfunda.com/articles/article524-net-best-practice-no-2-improve-garbage-collector-performance-using-finalizedispose-pattern.aspx

http://www.dotnetfunda.com/articles/article524-net-best-practice-no-2-improve-garbage-collector-performance-using-finalizedispose-pattern.aspx - http://codeidol.com/csharp/net-framework/Inside-the-CLR/Automatic-Memory-Management/