2008-11-27 26 views
51

Estoy tratando de averiguar cuánta memoria toman mis objetos para ver cuántos de ellos terminan en el Heap de objetos grandes (que es algo más de 85,000 bytes).Averigüe el tamaño de un objeto .net

Es tan simple como agregar 4 para un int, 8 para un largo, 4 (u 8 si tiene 64 bit) para cualquier tipo de referencia, etc. para cada objeto, o hay gastos generales para métodos, propiedades, etc.

+0

Pregunta relacionada: [sizeof Equivalente para tipos de referencia] (http://stackoverflow.com/questions/26570/sizeof-equivalent-for-reference-types) –

+0

Consulte esta pregunta, [Cómo obtener el tamaño de un campo en bytes con C#] [1], y en particular [Respuesta de Jon Skeets] [2] Básicamente, no es * tan simple como ... * [1]: http://stackoverflow.com/questions/207592/getting-the -size-of-a-field-in-bytes-with-c [2]: http://stackoverflow.com/questions/207592/getting-the-size-of-a-field-in-bytes-with -C# 207605 –

Respuesta

47

No olvide que el tamaño de un objeto real no incluye el tamaño de los objetos a los que hace referencia.

Las únicas cosas que probablemente terminen en el gran montón de objetos son las matrices y las cadenas; otros objetos tienden a ser relativamente pequeños en sí mismos. Incluso un objeto con (digamos) 10 variables de tipo de referencia (4 bytes cada una en x86) y 10 GUID (16 bytes cada una) solo ocupará unos 208 bytes (hay un poco de sobrecarga para la referencia de tipo y el bloque de sincronización).

Del mismo modo, al pensar en el tamaño de una matriz, no olvide que si el tipo de elemento es de referencia, solo el tamaño de las referencias cuenta para la matriz. En otras palabras, incluso si tiene una matriz con 20,000 elementos, el tamaño del objeto de matriz solo será un poco más de 80K (en x86) incluso si hace referencia a muchos más datos.

4

A menos que sea un gran tipo de valor o tipo de instancia (es decir, muchos miles de campos), los únicos tipos de los que debe preocuparse son las grandes matrices o cadenas. Por supuesto, para determinar el tamaño de una matriz, necesita saber el tamaño del elemento.

.NET (actualmente) alinea los tipos casi de la misma manera que los compiladores nativos alinean los tipos. tipos fundamentales tienen alineaciones naturales que son por lo general la potencia integral redondeado en marcha de dos más cercanos a su tamaño:

Single, Int32, UInt32 - 4 
IntPtr, UIntPtr, pointers, references - 4 on 32-bit, 8 on 64-bit 
Double, Int64, UInt64 - 8 
Char, Int16, UInt16 - 2 
Byte, SByte   - 1 

En el montaje de un tipo, el compilador se asegurará de que todos los campos de cualquier tipo dado tienen su desplazamiento inicial dentro de la instancia alineada a un límite que coincida con ese tipo, suponiendo que el diseño explícito no se esté utilizando.

Los tipos definidos por el usuario tienen una alineación, que se calcula como la alineación más alta de cualquiera de sus tipos de campo. El tamaño del tipo se amplía si es necesario para que el tamaño del tipo también esté alineado.

Pero, por supuesto, todos los tipos de referencia siguen teniendo tamaño y alineación IntPtr.Size, por lo que el tamaño del tipo de referencia no afectará a las matrices de ese tipo.

Tenga en cuenta que el CLR puede elegir, a su discreción, tipos de diseño diferentes a los descritos anteriormente, tal vez para aumentar la localidad de caché o reducir el relleno requerido por la alineación.

9

Está entrando en un área de depuración .NET avanzada. Comience con John Robins debugging books.

Use WinDBG con Sos.dll (parte de la distribución .NET) y Sosex.dll extensiones. Con estas herramientas, realmente puede ver lo que sucede cuando su aplicación se está ejecutando. Encontrarás respuestas a tus preguntas antes mencionadas.

(Otra recomendación sería la de instalar Shared Source CLI 2.0, también conocido como rotor 2, para ver lo que está pasando bajo el capó..)

9

Si puedes - serializarlo!

Dim myObjectSize As Long 

Dim ms As New IO.MemoryStream 
Dim bf As New Runtime.Serialization.Formatters.Binary.BinaryFormatter() 
bf.Serialize(ms, myObject) 
myObjectSize = ms.Position 
+0

Desafortunadamente, si serializas un objeto, también serializas todos los objetos que se refieren a –

+2

+1 porque esto es lo que realmente quería averiguar (no solo el tamaño de las referencias) – alldayremix

+1

@MatthewSteeples, un objeto sin sus componentes es una objeto vacío, por lo que si desea el "tamaño" de su contenedor, debe incluir los tamaños de los componentes. – serhio

34

Siga estos pasos para obtener el tamaño del objeto.

1) vaya a Visual Studio (2010) Propiedades del proyecto -> pestaña Depuración -> Habilite la depuración del código no administrado.

2) ir al menú de depuración de Visual Studio -> Opciones y configuraciones -> Depuración -> Símbolos.

3) No permiten símbolos de Microsoft Server, deje el valor predeterminado. (Símbolos pueden iniciar descarga)

4) Ajuste el punto de quiebre en su código, iniciar la depuración (F5).

5) Abrir depuración -> Windows -> Ventana Inmediata.

6) introducir .load sos.dll (Hijo de Huelga)

7) entrar! DumpHeap de tipo MiClase (el objeto que desea encontrar el tamaño)

8) desde la salida puso localizar el es decir, la dirección del objeto (00a8197c)

dirección MT Tamaño 00a8197c 00955124 36

9) a continuación,! ObjSize 00a8197c

10) Hay que ir -> sizeof (00a8197c) = 12 (0x48) bytes (MiClase) Método

+6

No sabía que podía usar sos.dll en visual studio. Muy útil, gracias. También podría ser útil tener en cuenta que sos.dll no se cargará si la aplicación está en modo de 64 bits. Ver http://stackoverflow.com/a/3548129/442078 – Will

+0

Asegúrate, sin embargo, de que entiendes los "inconvenientes" de '! ObjSize'. Tendrá en cuenta los ciclos en tu gráfico de objetos. Por ejemplo, si tiene un diccionario, con valores que hacen referencia al diccionario en sí, cada valor tendrá el "ObjSize" de todo el diccionario. –

5

de Gomes simplificado:

  1. ir a Visual Studio (2010) Propiedades del proyecto -> pestaña de depuración - > Habilitar la depuración del código no administrado.

  2. Establezca el punto de interrupción en su código, comience a depurar (F5).

  3. Abrir depuración -> Windows -> Ventana Inmediata.

  4. entrar .load sos

  5. ENTER (myObject reemplazar con el nombre de su objeto)

? String.Format ("{0: x}"., Integer.Parse (System.Runtime.InteropServices.GCHandle.InternalAddrOfPinnedObject (System.Runtime.InteropServices.GCHandle.Alloc (myObject) .GetHandleValue()) ToString()) - 4)

      6. uso resultado como parámetro de!ObjSize

véase: SOS.DLL, object Address and Visual Studio debugger Introduction

Ejemplo (estamos buscando objeto nombrado tbl):

.load sos 
extension C:\Windows\Microsoft.NET\Framework\v4.0.30319\sos.dll loaded 
? string.Format("{0:x}",Integer.Parse(System.Runtime.InteropServices.GCHandle.InternalAddrOfPinnedObject(System.Runtime.InteropServices.GCHandle.Alloc(tbl).GetHandleValue()).ToString())-4) 
"27ccb18" 
!ObjSize 27ccb18 
PDB symbol for clr.dll not loaded 
sizeof(027ccb18) =  154504 ( 0x25b88) bytes (System.Data.DataTable) 
0

Como una estimación (en 2017) puede depurar en su aplicación, establecer un punto de interrupción antes de su diccionario viene a la vida, toma una "instantánea de uso de memoria" (pestaña: uso de la memoria en Herramientas de diagnóstico), llena tu diccionario y obtén otra instantánea; no es exacto poner un buen gesto.

Cuestiones relacionadas