2009-04-02 28 views
5

Parece que el marco de entidad utiliza cantidades excesivas de memoria cuando inserta objetos nuevos en una base de datos.Uso de memoria de marco de entidad

for(int i = 0; i < numOwners; ++i) 
{ 
    var owner = Owner.CreateOwner(); 
    db.AddToOwnerSet(owner); 
    for(int j = 0; j < numChildren; ++j) 
    { 
     var child = Child.CreateChild(); 
     owner.Childs.Add(child); 
    } 
} 
db.SaveChanges(); 

En este punto, estos objetos contienen muy pocos elementos de datos. Al insertar 140,000 de estos objetos en la base de datos, el uso total de memoria de la aplicación fue de 600 MB y 1,2 gigabytes para 300,000. Estos objetos son pequeños, solo un nombre de cadena y una clave entera.

Puedo reducir el uso de memoria colocando llamadas de SaveChanges en el ciclo, pero luego el tiempo de ejecución empeora, y ya es bastante malo.

¿Alguien sabe por qué el marco de entidades está usando tanta memoria, o cómo conseguir que use menos memoria?

Respuesta

2

Dado que el entramado de entidades mantiene los datos en la memoria (al igual que muchos ORM), entonces, como ocurre con muchas colecciones en memoria, probablemente haya matrices internas. A medida que agrega elementos a una colección, la matriz interna se duplica en capacidad.

Por ejemplo, si tiene una colección como una ArrayList que contiene 256 elementos, y agrega el 257o elemento, entonces lo que sucede internamente es un nuevo bloque de memoria asignado para una matriz de 512 elementos, ellos 256 elemento matriz es copiado a la nueva matriz de 512 elementos, y luego la matriz de 256 elementos está disponible para la recolección de basura. Por lo tanto, en el punto de transición, tendrá 768 elementos asignados en la memoria solo porque haya agregado el 257. ° elemento. Me he encontrado con dolores de cabeza cuando uso Memorystream, porque necesitas casi 3 veces más memoria contigua no fragmentada de la que realmente necesitas. Esta es la propiedad .Capacity que se ve en las colecciones, y casi siempre es una potencia de 2 (ya que se duplica en tamaño según sea necesario).

Mi apuesta es que hay matrices internas que se duplican en tamaño según sea necesario para sus colecciones de objetos de memoria. Entonces, 300,000 objetos del mismo tipo probablemente se mantendrían en una matriz interna de tamaño 524,288. Además, si es similar a las técnicas similares en el .NEt Framework, cada vez que se agrega el 262145o elemento, tanto una matriz de 262144 como 524288 existía en la memoria mientras los elementos se copiaban en la nueva matriz. Un total de 786432 elementos en la memoria. La matriz anterior se mantendría hasta que el recolector de basura decidiera que ya no era necesaria.

Puede haber algunas opciones en el marco Entity con respecto al soporte de simultaneidad que podría deshabilitar, lo que podría mejorar el uso de la memoria. Sin embargo, aquí solo estoy especulando, pero para admitir la concurrencia almacenan en memoria tanto la versión actual de los datos, como su versión original para comparar y admitir la concurrencia.

También buscaría filtrar con qué datos está interactuando. Intente encontrar criterios inteligentes para limitar lo que se consulta y se carga en la memoria. Por ejemplo, si tenía una aplicación que permitía a un usuario editar cuentas de clientes, pero solo se le asignaban ciertas cuentas, entonces utilícela como su criterio de filtrado para que solo cargue en la memoria aquellas cuentas con las que el usuario podría interactuar.

1

Sus objetos pueden ser "pequeños" en términos de datos reales, pero cada objeto no es un DTO - Entity Framework adjunta una gran cantidad de código repetitivo a cada una de sus entidades, lo que significa que el tamaño real de cada objeto es bastante grande.

Si trabaja consistentemente con gráficos de objetos grandes, considere utilizar algo como NHibernate, que es estable, maduro y probado para funcionar. Entity Framework está muy rezagado en términos de características y rendimiento.

2

Sé que esta es una pregunta anterior, pero yo estaba experimentando el mismo problema hoy y me las arreglé para descubrir qué lo estaba causando.

Parece que la generación de los scripts SQL es responsable del gran salto en la memoria. Descubrí que crear procedimientos almacenados y vincularlos a mis objetos (pero me aseguro de que devuelva el valor para los identificadores como se muestra en this article) me ha salvado más de 300 MB de memoria.

Cuestiones relacionadas