2009-07-19 12 views
12

He leído sobre este tema en MSDN y en CLR a través de C#.¿Cuál es el punto de usar GC.AddMemoryPressure con un recurso no administrado?

Imagine que tenemos un HBITMAP no administrado de 2Mb asignado y un mapa de bits administrado de 8 bytes apuntando a él. ¿De qué sirve decirle al GC sobre esto con AddMemoryPressure si nunca va a poder hacer nada sobre el objeto, ya que está asignado como un recurso no administrado, por lo tanto, no susceptible a colecciones de basura?

Respuesta

9

El objetivo de AddMemoryPressure es indicar al recolector de elementos no utilizados que hay una gran cantidad de memoria asignada con ese objeto. Si no está administrado, el recolector de basura no lo sabe; solo la porción administrada. Dado que la porción administrada es relativamente pequeña, el GC puede dejarla pasar para la recolección de basura varias veces, esencialmente desperdiciando memoria que podría necesitar ser liberada.

Sí, todavía tiene que asignar manualmente y desasignar la memoria no administrada. No puedes escapar de eso. Simplemente usa AddMemoryPressure para asegurarse de que el GC sabe que está allí.

Editar:

Pues bien, en caso de que uno, yo podría hacerlo, pero había ninguna diferencia grande, como el GC no sería capaz de hacer una cosa sobre mi tipo , si entiendo esto correctamente: 1) Declararía mi variable, 8 bytes administrados, 2 MB de bytes no administrados. Entonces lo usaría, llamaré a eliminar, para que la memoria no administrada sea liberada. En este momento solo ocupará 8 bytes. Ahora, a mis ojos, haber llamado en el comienzo AddMemoryPressure y RemoveMemoryPressure al final no habría hecho nada diferente. ¿Qué me estoy equivocando? Perdón por ser tan molesto con esto. - Jorge Branco

Creo que veo su problema.

Sí, si puede garantizar que siempre llama al Dispose, entonces sí, no necesita molestarse con AddMemoryPressure y RemoveMemoryPressure. No hay equivalencia, ya que la referencia todavía existe y el tipo nunca se recopilará.

Dicho esto, aún desea utilizar AddMemoryPressure y RemoveMemoryPressure, para mayor completitud. ¿Qué sucede si, por ejemplo, el usuario de su clase olvidó llamar a Dispose?En ese caso, suponiendo que implementó correctamente el patrón de eliminación, terminará recuperando los bytes no administrados en la finalización, es decir, cuando se recopila el objeto gestionado. En ese caso, desea que la presión de memoria permanezca activa, de modo que es más probable que se reclame el objeto.

+0

Bueno, eso no respondió la pregunta, lol. –

+0

Dije casi exactamente lo que dijo Steven Lyons, solo de una manera diferente. ¿Cómo no respondió la pregunta? – Randolpho

+0

Bueno, en realidad lo volví a leer y edité mi publicación. –

13

Se proporciona para que el GC conozca el costo real del objeto durante la recolección. Si el objeto es realmente más grande de lo que refleja el tamaño gestionado, puede ser candidato para una colección rápida (er).

Brad Abrams entry de esto es bastante claro:

Considérese una clase que tiene una muy pequeña Tamaño administrado por ejemplo, pero mantiene un puntero en gran parte de memoria no administrada. Incluso después de que nadie haga referencia a la instancia administrada, podría permanecer activo por un tiempo porque el GC ve solo el tamaño de la instancia administrada , no cree que "vale " para liberar la instancia. Entonces necesitamos para "enseñar" al GC sobre el verdadero costo de esta instancia para que sepa saber exactamente cuándo patear una colección para liberar más memoria en el proceso .

+0

En realidad, ahora que volví a leer su publicación, mi pregunta sigue en pie. Después de usar mi mapa de bits, voy a llamar a disponer de él, por lo que en realidad solo tomará 8 bytes de memoria. Si, por otro lado, no llamé a dispose, bueno, entonces realmente ocuppies 2mb de memoria. Existe el tercer caso de que no hay un método de eliminación, por lo que el GC no puede hacer nada por ello. Entonces, el GC que conozca el tamaño real del tipo solo ayudará en la situación 2. ¿O me estoy perdiendo algo? –

+0

En el caso 1, querrá llamar a GC.AddMemoryPressure en la asignación de mapa de bits y luego GC.RemoveMemoryPressure cuando libere manualmente el mapa de bits. Eso asegurará que el objeto refleje correctamente su tamaño al GC. Sin embargo, si hay una manera de asegurarse de que el GC nunca se ejecute mientras su objeto es elegible para la recopilación y se asigna el mapa de bits, estos métodos pueden no importar. –

+0

Bueno, en el caso uno, podría hacerlo, pero no haría una gran diferencia, ya que el GC no sería capaz de hacer algo acerca de mi tipo, si entiendo esto correctamente: 1) Yo declararía mi variable, 8 bytes administrados, 2mb bytes no administrados. Entonces lo usaría, llamaré a eliminar, para que la memoria no administrada sea liberada. En este momento solo ocupará 8 bytes. Ahora, a mis ojos, haber llamado en el comienzo AddMemoryPressure y RemoveMemoryPressure al final no habría hecho nada diferente. ¿Qué me estoy equivocando? Perdón por ser tan molesto con esto. –

2

Ponlo de esta manera, suponiendo que los objetos administrados de 8 bytes cada uno se refieren a una imagen no administrada de 2 MB. El GC puede esperar mucho tiempo antes de recolectar cientos o miles de pequeños objetos administrados, porque son muy pequeños. Eso significa que también cientos o miles de fragmentos enlazados de 2 MB no administrados permanecerán vivos, a la espera de ser eliminados. Eso podría convertirse en un gran problema. Al agregar 2 MB de presión de memoria en el constructor, hará que GC piense que el objeto gestionado no tiene 8 bytes, sino 8 bytes + 2 MB. Eso desencadenará la forma de recolección más temprano.

No olvide la llamada Eliminar.

Por supuesto, si te deshaces de ti mismo, entonces no necesitarás todo eso.

Cuestiones relacionadas