¿De donde sale este DataRow?
Hace poco gracias al equipo DOT de PlainConcepts, tuve oportunidad de participara en un caso muy interesante, el software de la empresa en cuestión tenía un problema de fuga de memoria porque las referencias de los objetos no eran recolectadas por el GC, así que WinDGB en mano me puse a averiguar porque era.
Una de las primeras cosas que se hace cuando te encuentras un caso como este es intentar que la aplicación que vas a depurar se encuentre en ese caso, ósea que este fugando memoria, en mi caso lo era así que el segundo paso es hacer un dump completo de la aplicación. Esto lo podemos hacer con una herramienta que viene en la carpeta de instalación del “Debugging tools for Windows” que se llama ADPlus.vbs, la sintaxis sería la siguiente:
adplus -hang -pn miprograma.exe
Una vez hecho eso tenemos un dump completo de la aplicación en el estado de fuga de memoria que os comentaba antes, ahora tenemos que ponernos a investigar. Una de las cosas que suelo hacer siempre que me encuentro con un caso de fuga de memoria es hacer un !dumpheap para ver que nos encontramos en el heap (monton) de .NET, que es básicamente donde están todos los objetos que se instancian en el ciclo de vida de una aplicación .NET.
Aquí podemos ver el resultado en WinDBG:
0:003> !dumpheap -stat total 5003168 objects Statistics: MT Count TotalSize Class Name 6b441898 1 12 System.Collections.Generic.GenericEqualityComparer`1[[System.String, mscorlib]] 6b440b48 1 12 System.Security.Permissions.ReflectionPermission 6b43f850 1 12 System.Resources.FastResourceComparer 6b43ccec 1 12 System.__Filters 6b43cc9c 1 12 System.Reflection.Missing 6b43cba4 1 12 System.RuntimeType+TypeCacheQueue 6b43bcb8 1 12 System.Runtime.InteropServices.GCHandle 6b439cf0 1 12 System.RuntimeTypeHandle 6b4382c8 1 12 System.Text.DecoderExceptionFallback 6b438284 1 12 System.Text.EncoderExceptionFallback 6b41c7a8 1 12 System.Security.Permissions.FileDialogPermission 6b41c76c 1 12 System.Security.PolicyManager 6b41abec 1 12 System.Reflection.__Filters 6b41a004 1 12 System.DBNull 61e8508c 1 12 System.Data.IndexField[] 61e7f984 1 12 Bid+BindingCookie 00584a78 1 12 DataRowMemoryLeak.Foo 6ba6bc08 1 16 System.IO.TextReader+SyncTextReader 6b440ca0 1 16 System.Enum+HashEntry 6b43fad4 1 16 System.Resources.ResourceReader+TypeLimitingDeserializationBinder 6b43a0d8 1 16 System.Int64 6b439ef0 1 16 System.Globalization.GlobalizationAssembly 6b417760 1 16 System.Security.Permissions.UIPermission 61e85f8c 1 16 System.Data.DataRowBuilder 6b445bd4 1 20 System.Environment+ResourceHelper 6b441bac 1 20 System.Security.Permissions.EnvironmentPermission 6b438988 1 20 System.Text.StringBuilder 6b437a6c 1 20 Microsoft.Win32.SafeHandles.SafeFileMappingHandle 6b437a14 1 20 Microsoft.Win32.SafeHandles.SafeViewOfFileHandle 6b437988 1 20 System.Text.InternalEncoderBestFitFallback 61e85754 1 20 System.Data.DataRowCollection 61e7f9c0 1 20 Bid+AutoInit 6b4447e8 1 24 System.Collections.BitArray 6b441914 1 24 System.String[][] 6b440e8c 2 24 System.OrdinalComparer 6b43a470 1 24 System.OperatingSystem 6b437d2c 1 24 System.IO.TextWriter+SyncTextWriter 6b4379d4 1 24 System.Text.InternalDecoderBestFitFallback 6b421078 1 24 System.Collections.Generic.List`1[[System.Int32, mscorlib]] 6b4192a0 1 24 System.Collections.Generic.List`1[[System.WeakReference, mscorlib]] 6b417bb0 1 24 System.Collections.Stack 61e85e44 1 24 System.Collections.Generic.List`1[[System.Data.Index, System.Data]] 61e854f8 1 24 System.Collections.Generic.List`1[[System.Data.DataViewListener, System.Data]] 61e8520c 1 24 System.Collections.Generic.List`1[[System.Data.DataView, System.Data]] 61e7da60 1 24 <CrtImplementationDetails>.ModuleUninitializer 6b43ecb4 1 28 System.Text.DecoderNLS 6b438f18 1 28 System.SharedStatics 6b4383a8 1 28 System.IO.Stream+NullStream 6b438188 1 28 System.Text.EncoderNLS 6b437bfc 1 28 Microsoft.Win32.Win32Native+InputRecord 6b441c5c 1 32 System.Text.UnicodeEncoding+Decoder 6b43ec2c 1 32 System.Text.UTF8Encoding+UTF8Decoder 6b43ae5c 1 32 System.Security.PermissionTokenFactory 6b43820c 1 32 System.Threading.IOCompletionCallback 6b438108 1 32 System.Text.UTF8Encoding+UTF8Encoder 6b41cbd8 1 32 System.Security.Util.Tokenizer+StringMaker 6b415650 1 32 System.Runtime.CompilerServices.RuntimeHelpers+CleanupCode 6b4155c4 1 32 System.Runtime.CompilerServices.RuntimeHelpers+TryCode 6b415394 1 32 System.Text.UnicodeEncoding 61e856e4 1 32 System.Data.ConstraintCollection 61e85630 1 32 System.Data.RecordManager 61e7f90c 1 32 Bid+CtrlCB 6b43ac78 1 36 System.Security.Permissions.FileIOPermission 6b43a028 1 36 System.Int64[] 6b41d0e0 3 36 System.Security.Policy.AllMembershipCondition 6b418058 1 36 System.Resources.RuntimeResourceSet 6b43fa50 1 40 System.Runtime.Serialization.Formatters.Binary.BinaryFormatter 6b43f694 1 40 System.IO.BinaryReader 6b43d778 2 40 Microsoft.Win32.SafeHandles.SafeFileHandle 6b43adb0 2 40 System.Security.PermissionToken 6b41edfc 1 40 System.Int32[][] 6b439338 1 44 System.AppDomainSetup 6b415be0 1 44 System.Threading.ReaderWriterLock 61e87720 1 44 System.Data.Common.StringStorage 61e875fc 1 44 System.Data.Common.Int32Storage 61e857c4 1 44 System.Data.DataRowCollection+DataRowTree 6b440e18 3 48 System.CultureAwareComparer 6b43d9e4 4 48 System.UInt16 6b43ba44 3 48 System.Text.DecoderReplacementFallback 6b43b9f4 3 48 System.Text.EncoderReplacementFallback 6b43a3f4 2 48 System.Version 6b41d2a0 4 48 System.Security.Permissions.StrongNamePublicKeyBlob 6b43f74c 1 52 System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[System.Resources.ResourceLocator, mscorlib]] 6b415314 1 52 System.Resources.ResourceManager 6b43b8f0 2 56 System.Text.UTF8Encoding 6b438e20 1 56 System.Threading.Thread 6b4164b4 1 56 System.LogLevel[] 61e85674 1 56 System.Data.DataColumnCollection 6b440be4 1 60 System.UInt64[] 6b4242f8 1 60 System.IO.StreamReader+NullStreamReader 6b42420c 1 60 System.IO.StreamReader 6b41ac44 2 64 System.Reflection.TypeFilter 6b4190d8 2 64 System.EventHandler 6b43b674 1 68 System.Globalization.CultureTable 6b439d98 3 72 System.Reflection.Assembly 6b438b90 1 72 System.ExecutionEngineException 6b438b00 1 72 System.StackOverflowException 6b438a70 1 72 System.OutOfMemoryException 6b437c50 2 72 System.IO.__ConsoleStream 6b43786c 1 76 System.Text.SBCSCodePageEncoding 6b41d320 5 80 System.Security.Policy.ZoneMembershipCondition 6b41d230 4 80 System.Security.Policy.PolicyStatement 6b417fdc 1 80 System.Resources.ResourceReader 6b43cd48 3 96 System.Reflection.MemberFilter 6b43c23c 2 96 System.Reflection.Module 6b43a72c 8 96 System.Security.Permissions.SecurityPermission 6b4156d4 3 96 System.Globalization.CompareInfo 6b43cc64 1 100 System.Reflection.MetadataArgs+SkipAddresses 6b43b708 5 100 System.Globalization.CultureTableItem 6b43902c 1 100 System.AppDomain 6b4163c0 1 108 System.SwitchStructure[] 6b437e88 2 112 System.IO.StreamWriter 6b416db0 2 120 System.Collections.Hashtable+SyncHashtable 6b439f44 2 128 System.IO.UnmanagedMemoryStream 6b422314 4 128 System.Collections.ArrayList+SyncArrayList 6b417b4c 7 140 Microsoft.Win32.SafeHandles.SafeRegistryHandle 6b43a510 4 144 System.Security.PermissionSet 6b438c20 2 144 System.Threading.ThreadAbortException 6b41f04c 3 156 System.Security.Policy.PolicyLevel 6b43ae10 5 180 System.Security.Util.TokenBasedSet 6b43aa98 17 204 System.Int32 6b41794c 7 224 Microsoft.Win32.RegistryKey 6b43b7b0 2 256 System.Globalization.NumberFormatInfo 6b438468 22 264 System.Object 61e84fb4 2 296 System.Data.DataColumn 61e82cc8 1 296 System.Data.DataTable 6b43b624 7 336 System.Globalization.CultureTableRecord 6b43fc20 1 352 System.Collections.Generic.Dictionary`2+Entry[[System.String, mscorlib],[System.Resources.ResourceLocator, mscorlib]][] 6b41ce18 10 360 System.Security.Policy.UnionCodeGroup 6b43b448 6 408 System.Globalization.CultureInfo 6b41f0a4 9 432 System.Security.NamedPermissionSet 6b43aea0 18 1008 System.Collections.Hashtable 6b41cd3c 65 1560 System.Security.Policy.StrongNameMembershipCondition 6b43b2bc 12 1676 System.Byte[] 6b4399cc 110 2200 System.RuntimeType 6b43af9c 18 2664 System.Collections.Hashtable+bucket[] 6b43947c 24 3444 System.Char[] 6b41cae8 216 6048 System.Security.SecurityElement 6b43a87c 266 6384 System.Collections.ArrayList 61e85bd0 347 9716 System.Data.RBTree`1+TreePage[[System.Data.DataRow, System.Data]] 00466bf0 235 395780 Free 6b43a9e8 368 4455624 System.Int32[] 6b43884c 1000553 31651760 System.String 61e85d88 347 32089008 System.Data.RBTree`1+Node[[System.Data.DataRow, System.Data]][] 6b414e78 320 37795900 System.Object[] 6b415b88 2999997 47999952 System.WeakReference 61e85048 999999 63999936 System.Data.DataRow Total 5003168 objects
El caso es que tenía aproximadamente un millón de instancias de la clase System.Data.DataRow, que como bien sabéis representa una fila de un DataTable de ADO.NET, pues resulta que la aplicación por algún motivo seguía teniendo las referencias a esas DataRow.
Ya sabemos cuál es el problema, ahora tenemos que saber desde donde se referencia a esas DataRow y encontrar el trozo de código que lo hace, esto normalmente es lo más complicado porque tiene que conocer el software que estás depurando y en mi caso son clientes externos y no conozco el caso, así que lo que normalmente hago son dos cosas:
· Con el comando !gcroot le paso una dirección de memoria de uno de esos DataRow para ver desde que Thread y que pila se ha referenciado el objeto. Con el identificador del Thread cambio el WinDGB del Thread actual al nuevo thread con el comando “~23s” siendo 23 el identificador del Thread y ahora ejecuto un !clrstack con el que puedo ver la pila administrada del Thread actual. Ahora simplemente tengo que buscar en esas clases y en esos métodos referencias a los DataRows para encontrar la fuente de las referencias. Además puedo utilizar el comando !dso que me permite ver los parámetros de las funciones y las variables locales de todos lo métodos de la pila actual.
0:000> !dso
OS Thread Id: 0x7a0 (0)
ESP/REG Object Name
0030ef94 13cff17c Microsoft.Win32.SafeHandles.SafeFileHandle
0030efa4 13cff17c Microsoft.Win32.SafeHandles.SafeFileHandle
0030efd8 13cff3e0 System.Byte[]
0030efdc 13cff190 System.IO.__ConsoleStream
0030effc 13cff1c0 System.IO.StreamReader
0030f000 13cff1c0 System.IO.StreamReader
0030f018 13cff1c0 System.IO.StreamReader
0030f01c 13cff6f8 System.IO.TextReader+SyncTextReader
0030f03c 13cff6f8 System.IO.TextReader+SyncTextReader
0030f060 13cfe1b8 System.Int64
0030f064 1017bd90 System.String total memory -
0030f068 13cfe1a8 System.WeakReference
0030f06c 0b597af8 System.Data.DataRow
0030f070 0180a954 System.Data.DataRowCollection
0030f074 01866d48 System.Collections.Generic.List`1[[System.WeakReference, mscorlib]]
0030f078 0180a954 System.Data.DataRowCollection
0030f07c 13cfe1ec System.String total memory - 218038312
0030f080 13cfe1b8 System.Int64
0030f084 1017bd90 System.String total memory -
0030f088 01866d70 System.Data.DataTable
0030f0a4 01866d3c DataRowMemoryLeak.Foo
0030f0b4 0b597af8 System.Data.DataRow
0030f0b8 0180a954 System.Data.DataRowCollection
0030f0bc 01866d48 System.Collections.Generic.List`1[[System.WeakReference, mscorlib]]
0030f0c0 0180a954 System.Data.DataRowCollection
0030f0c4 01866d70 System.Data.DataTable
0030f0c8 01866d3c DataRowMemoryLeak.Foo
0030f0e8 0b597af8 System.Data.DataRow
0030f0ec 0180a954 System.Data.DataRowCollection
0030f0f0 01866d48 System.Collections.Generic.List`1[[System.WeakReference, mscorlib]]
0030f0f4 0180a954 System.Data.DataRowCollection
0030f0f8 01866d70 System.Data.DataTable
0030f0fc 01866d3c DataRowMemoryLeak.Foo
0030f118 01866d24 System.String ID
0030f120 0180a954 System.Data.DataRowCollection
0030f12c 01866d08 System.String Name
0030f13c 01866d24 System.String ID
0030f148 01866d08 System.String Name
0030f150 01866d70 System.Data.DataTable
0030f154 01866d3c DataRowMemoryLeak.Foo
0030f158 0b597af8 System.Data.DataRow
0030f15c 01866d70 System.Data.DataTable
0030f160 01866d3c DataRowMemoryLeak.Foo
0030f16c 0180a1dc System.Object[] (System.String[])
0030f400 0180a1dc System.Object[] (System.String[])
0:000> !gcroot 088a1630 Note: Roots found on stacks may be false positives. Run "!help gcroot" for more info. eax: 0030eec4 (invalid object) Scan Thread 0 OSTHread 7a0 ESP:30eeb4: 0030eec4 (invalid object) ESP:30f06c:Root:0b597af8(System.Data.DataRow)-> 01866d70(System.Data.DataTable)-> 0180a954(System.Data.DataRowCollection)-> 0180a968(System.Data.DataRowCollection+DataRowTree)-> 07f166bc(System.Object[])-> 0b033360(System.Data.RBTree`1+TreePage[[System.Data.DataRow, System.Data]])-> 088a1630(System.Data.RBTree`1+Node[[System.Data.DataRow, System.Data]][])
· Si todo esto no funciona también puedo hacer otro tipo de análisis de la aplicación. Con el Reflecto, programa que por cierto todo programador de .net debería de tener, podemos agregar la referencia del ensamblado el cual queremos analizar y el ensamblado de la clase la cual queremos saber si nuestro ensamblado referencia. En este caso miEnsamblado.dll y System.Data.dll que contiene System.Data.DataRow y pulsando el botón contrario encima de la clase tengo la opción de Analyze que me permite ver varias opciones.
- Depends On
- Used By
- Exposed By
- Instantiated By
· Como podréis imaginar las dos que me interesan son Used By y Instantiated By, en este caso Instantiated By no tanto porque no soy el responsable directo de crear las instancias de los DataRow, pero Used By me va a permitir ver de los ensamblados que tengo cargados cuales referencia a esta clase.
Así que como podéis ver la vida de un depurador no es fácil pero hay una serie de trucos que os pueden ayudar a solucionar la vida.
Espero que os haya gustado y hasta otra.
Saludos. Luis.
Actualización: (16 enero 2008)
Aquí esta la URL del ejemplo usado con WinDGB, http://www.luisguerrero.net/downloads/DataRowMemoryLeak.zip
Para sacar una dirección de memoria de un objeto y después usarlo para por ejemplo !do (DumpObject) o !gcroot tenemos que usar el comando !dumpheap que nos muestra toda la lista de objetos de hay en el heap (montón).net,SOS,Trucos.
Si hacemos un comando como este: !dumpheap –type System.Data.DataRow tenemos lo siguiente:
Address MD
0b6d6598 77a95048 64
0b6d65f8 77a95048 64
0b6d6658 77a95048 64
0b6d66b8 77a95048 64
0b6d6718 77a95048 64
0b6d6778 77a95048 64
0b6d67d8 77a95048 64
0b6d6838 77a95048 64
0b6d6898 77a95048 64
0b6d68f8 77a95048 64
0b6d6958 77a95048 64
0b6d69b8 77a95048 64
0b6d6a18 77a95048 64
0b6d6a78 77a95048 64
total 1000696 objects
Statistics:
MT Count TotalSize Class Name
77a95f8c 1 16 System.Data.DataRowBuilder
77a95754 1 20 System.Data.DataRowCollection
77a957c4 1 44 System.Data.DataRowCollection+DataRowTree
77a95bd0 347 9716 System.Data.RBTree`1+TreePage[[System.Data.DataRow, System.Data]]
77a95d88 347 32089008 System.Data.RBTree`1+Node[[System.Data.DataRow, System.Data]][]
77a95048 999999 63999936 System.Data.DataRow
Total 1000696 objects
0:004> !do 0b6d6a78
Name: System.Data.DataRow
MethodTable: 77a95048
EEClass: 779adf30
Size: 64(0x40) bytes
(C:\Windows\assembly\GAC_32\System.Data\2.0.0.0__b77a5c561934e089\System.Data.dll)
Fields:
MT Field Offset Type VT Attr Value Name
77a92cc8 4000720 4 ...em.Data.DataTable 0 instance 01956d70 _table
77a95674 4000721 8 ...aColumnCollection 0 instance 018fa804 _columns
71ebaa98 4000722 18 System.Int32 1 instance -1 oldRecord
71ebaa98 4000723 1c System.Int32 1 instance 999964 newRecord
71ebaa98 4000724 20 System.Int32 1 instance -1 tempRecord
71ebaa98 4000725 24 System.Int32 1 instance 999965 _rowID
77ea7fc8 4000726 28 System.Int32 1 instance 0 _action
71ebea68 4000727 38 System.Boolean 1 instance 0 inChangingEvent
71ebea68 4000728 39 System.Boolean 1 instance 0 inDeletingEvent
71ebea68 4000729 3a System.Boolean 1 instance 0 inCascade
77a94fb4 400072a c ...m.Data.DataColumn 0 instance 00000000 _lastChangedColumn
71ebaa98 400072b 2c System.Int32 1 instance 0 _countColumnChange
77ec3bf4 400072c 10 ...em.Data.DataError 0 instance 00000000 error
71eb8468 400072d 14 System.Object 0 instance 00000000 _element
71ebaa98 400072e 30 System.Int32 1 instance 22676893 _rbTreeNodeId
71ebaa98 4000730 34 System.Int32 1 instance 999965 ObjectID
71ebaa98 400072f 498 System.Int32 1 static 999999 _objectTypeCount
0:004> !dumpmt 77a95048
EEClass: 779adf30
Module: 779a1000
Name: System.Data.DataRow
mdToken: 02000081 (C:\Windows\assembly\GAC_32\System.Data\2.0.0.0__b77a5c561934e089\System.Data.dll)
BaseSize: 0x40
ComponentSize: 0x0
Number of IFaces in IFaceMap: 0
Slots in VTable: 99
De la primera columna podemos sacar la dirección del objeto que queremos investigar.
Pingback: forklift hire auckland
Pingback: pumps
Pingback: {Legalsounds|Download music}
Pingback: auckland lighting
Pingback: Angry Birds Game Pc
Pingback: show display
Pingback: cool caravans
Pingback: rx7 rx
Pingback: psychic
Pingback: Download chart music
Pingback: new zealand business sale
Pingback: master unblocker
Pingback: phentermine jaw clenching
Pingback: where can i drive a race car
Pingback: screen doors nz
Pingback: equipment rental
Pingback: Aktuelle Treppenlift Preise
Pingback: watches
Pingback: snowboard size
Pingback: Solar Yard Lights
Pingback: ice machine maker
Pingback: Protection
Pingback: mma gyms
Pingback: Adult Cloud Tube
Pingback: history of technology in education in the philippines
Pingback: tiu 1
Pingback: seksfilm
Pingback: cloud hosting
Pingback: cat scan vs mri
Pingback: true nutrition
Pingback: Ringing Ears Dehydration
Pingback: botiquin
Pingback: Free Poker Bankroll
Pingback: true nutrition
Pingback: Keely
Pingback: is wartrol a scam
Pingback: Adult Social Networking
Pingback: wartrol for genital warts
Pingback: iPhone 5 Release Date
Pingback: poilsines keliones
Pingback: Great Clip Coupons Printable 2010
Pingback: austrian silver philharmonic coin
Pingback: LED Light Bulbs wholesale
Pingback: iPhone 5
Pingback: Great Clips Coupons Alexandria
Pingback: Great Clips Coupons Albertville
Pingback: Great Clips Printable Coupons 2011
Pingback: Lower Back Muscles
Pingback: voile curtains
Pingback: bad breath cure
Pingback: surgery abroad
Pingback: how to stop biting fingernails
Pingback: kindle for sale
Pingback: lose weight fast
Pingback: cash advances online
Pingback: közösségi portálok
Pingback: fxs
Pingback: lana pengar snabbt
Pingback: scrap car collection
Pingback: SEO link monster review
Pingback: how to become a porn star