DataTable在内存中是如何存储一张表的结构的呢?如何使用Windbg直接在内存中找到一个DataTable里面的第M列第N行的值呢?这的确是一个比较有趣的问题^_^
下面的内容,主要是讲如何用windbg+sos来看看一个DataTable在内存中是如何存储的,以及寻找内存中一个DataTable特定的行列的一个单元的值是多少。同时,还有一点Windbg Script的使用。
找一个小白鼠先:
class Program
{
static void Main(string[] args)
{
System.Data.DataTable dt = new System.Data.DataTable();
DataColumn dtC1 = new DataColumn();
dtC1.ColumnName = "Column1";
DataColumn dtC2 = new DataColumn();
dtC2.ColumnName = "Column2";
dt.Columns.Add(dtC1);
dt.Columns.Add(dtC2);
DataRow dr1 = dt.NewRow();
dr1["Column1"] = "aaaa";
dr1["Column2"] = "bbbb";
dt.Rows.Add(dr1);
DataRow dr2 = dt.NewRow();
dr2["Column1"] = "cccc";
dr2["Column2"] = "dddd";
dt.Rows.Add(dr2);
pause();
}
public static void pause()
{
System.Console.ReadLine();
}
}
下面就看看DataTable在内存里面是如何存储的,以及在内存里面找到aaaa,bbbb,cccc,dddd这几个字符串。
首先!threads看看哪几个托管线程,then,切换到主线程上面:~0s
0:000> !dumpstackobjects
OS Thread Id: 0x66c (0)
ESP/REG Object Name
0012f3b0 013b9830 Microsoft.Win32.SafeHandles.SafeFileHandle
0012f3c0 013b9830 Microsoft.Win32.SafeHandles.SafeFileHandle
0012f3f4 013ba01c System.Byte[]
0012f3f8 013b9844 System.IO.__ConsoleStream
0012f418 013b97c8 System.Data.DataRow
0012f41c 013b9fc4 System.IO.StreamReader
0012f420 013b9fc4 System.IO.StreamReader
0012f424 013b7dac System.Data.DataRowCollection
0012f434 013b9fc4 System.IO.StreamReader
0012f438 013ba338 System.IO.TextReader+SyncTextReader
0012f43c 013b7dac System.Data.DataRowCollection
0012f444 013b97c8 System.Data.DataRow
0012f448 013b9664 System.Data.DataRow
0012f44c 013ba338 System.IO.TextReader+SyncTextReader
0012f450 013b7dac System.Data.DataRowCollection
0012f458 013b6120 System.Data.DataTable
0012f468 013b5b7c System.Object[] (System.String[])
0012f46c 013b82fc System.Data.DataColumn
0012f470 013b8edc System.Data.DataColumn
0012f534 013b5b7c System.Object[] (System.String[])
0012f6e0 013b5b7c System.Object[] (System.String[])
0012f708 013b5b7c System.Object[] (System.String[])
有几个DataColumn和几个DataRow,还有两个DataRowCollection。为了证实猜想,继续查看下去,dump DataTable:
0:000> !do 013b6120
Name: System.Data.DataTable
MethodTable: 653c46d8
EEClass: 653c4288
Size: 296(0x128) bytes
Fields:
MT Type Value Name
|
7a745c0c |
...ponentModel.ISite |
000000000 |
site |
|
7a742e54 |
....EventHandlerList |
000000000 |
events |
|
790f9c18 |
System.Object |
000000000 |
EventDisposed |
|
653c2e2c |
System.Data.DataSet |
000000000 |
dataSet |
|
653c6ce8 |
System.Data.DataView |
000000000 |
defaultView |
|
653c72cc |
...DataRowCollection |
0013b7dac |
rowCollection |
|
653c33d4 |
...aColumnCollection |
0013b7c5c |
columnCollection |
|
653c711c |
...straintCollection |
0013b7d74 |
constraintCollection |
|
653d3d0c |
...elationCollection |
000000000 |
parentRelationsCollection |
|
653d3d0c |
...elationCollection |
000000000 |
childRelationsCollection |
|
653c7080 |
...ata.RecordManager |
0013b7500 |
recordManager |
|
790fa3e0 |
System.String |
0013b6290 |
tableName |
|
790fa3e0 |
System.String |
000000000 |
tableNamespace |
|
790fa3e0 |
System.String |
0013b6290 |
tablePrefix |
|
653e63bc |
...ta.DataExpression |
000000000 |
displayExpression |
|
790ff4c4 |
...ation.CultureInfo |
0013b78dc |
_culture |
|
7910feec |
...ation.CompareInfo |
000000000 |
_compareInfo |
|
790ffdcc |
...m.IFormatProvider |
000000000 |
_formatProvider |
|
79112d98 |
...em.StringComparer |
000000000 |
_hashCodeProvider |
|
790fa3e0 |
System.String |
000000000 |
encodedTableName |
|
653c3e94 |
...m.Data.DataColumn |
000000000 |
xmlText |
|
653c3e94 |
...m.Data.DataColumn |
000000000 |
_colUnique |
|
79105ba4 |
System.Decimal |
1013b6224 |
minOccurs |
|
79105ba4 |
System.Decimal |
1013b6234 |
maxOccurs |
|
790f9c18 |
System.Object |
000000000 |
typeName |
|
653c9b84 |
....UniqueConstraint |
000000000 |
primaryKey |
|
653d63ac |
...Data.IndexField |
0013b6274 |
_primaryIndex |
|
653c75f8 |
System.Data.Index |
000000000 |
loadIndexwithOriginalAdded |
|
653c75f8 |
System.Data.Index |
000000000 |
loadIndexwithCurrentDeleted |
|
79124228 |
System.Object[] |
000000000 |
EmptyDataRowArray |
|
7a74db40 |
...criptorCollection |
000000000 |
propertyDescriptorCollectionCache |
|
79124228 |
System.Object[] |
0013b6280 |
_nestedParentRelations |
|
653dfc68 |
...hangeEventHandler |
000000000 |
onRowChangedDelegate |
|
653dfc68 |
...hangeEventHandler |
000000000 |
onRowChangingDelegate |
|
653dfc68 |
...hangeEventHandler |
000000000 |
onRowDeletingDelegate |
|
653dfc68 |
...hangeEventHandler |
000000000 |
onRowDeletedDelegate |
|
653dec84 |
...hangeEventHandler |
000000000 |
onColumnChangedDelegate |
|
653dec84 |
...hangeEventHandler |
000000000 |
onColumnChangingDelegate |
|
653e039c |
...ClearEventHandler |
000000000 |
onTableClearingDelegate |
|
653e039c |
...ClearEventHandler |
000000000 |
onTableClearedDelegate |
|
653e042c |
...ewRowEventHandler |
000000000 |
onTableNewRowDelegate |
|
7a7638a4 |
...angedEventHandler |
000000000 |
onPropertyChangingDelegate |
|
7910d61c |
System.EventHandler |
000000000 |
onInitialized |
|
653c7730 |
...ta.DataRowBuilder |
0013b82ec |
rowBuilder |
|
790fea70 |
...ections.Hashtable |
000000000 |
rowDiffId |
|
79103b6c |
....ReaderWriterLock |
0013b6348 |
indexesLock |
|
791240f0 |
System.Int32[] |
0013b6248 |
zeroIntegers |
|
79124228 |
System.Object[] |
0013b6254 |
zeroColumns |
|
79124228 |
System.Object[] |
0013b6264 |
zeroRows |
|
653d63ac |
...Data.IndexField |
0013b6274 |
zeroIndexField |
|
79124228 |
System.Object[] |
0013b6280 |
EmptyArrayDataRelation |
由于DataTable里面的东西太多,就去掉了几列和一些没有太大用处的行。在elementColumnCount属性里面,可以看到DataTable里面有刚才定义的两列。
接着,可以在columnCollection这个field里面找到刚才小白鼠里面的DataTable的Column的集合:
0:000> !do 013b7c5c
Name: System.Data.DataColumnCollection
MethodTable: 653c33d4
EEClass: 653c3364
Size: 56(0x38) bytes
(C:\WINDOWS\assembly\GAC_32\System.Data\2.0.0.0__b77a5c561934e089\System.Data.dll)
Fields:
MT Type Value Name
7a753b14 ...onChangeEventArgs 00000000 RefreshEventArgs
653c46d8 ...em.Data.DataTable 013b6120 table
791036b0 ...ections.ArrayList 013b7c94 _list
790fed1c System.Int32 1 defaultNameIndex
79124228 System.Object[] 00000000 delayedAddRangeColumns
790fea70 ...ections.Hashtable 013b7cac columnFromName
7a7504bc ...hangeEventHandler 00000000 onCollectionChangedDelegate
7a7504bc ...hangeEventHandler 00000000 onCollectionChangingDelegate
7a7504bc ...hangeEventHandler 00000000 onColumnPropertyChangedDelegate
79104f64 System.Boolean 0 fInClear
79124228 System.Object[] 013b6254 columnsImplementingIChangeTracking
790fed1c System.Int32 0 nColumnsImplementingIChangeTracking
790fed1c System.Int32 0
nColumnsImplementingIRevertibleChangeTracking
在这个结构中,可以看到DataColumn是放过在_list这个ArrayList里面的。继续查看ArrayList里面都有些什么:
0:000> !dumpobj 013b7c94
Name: System.Collections.ArrayList
MethodTable: 791036b0
EEClass: 79103604
Size: 24(0x18) bytes
(C:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
Fields:
MT Field Offset Type VT Attr Value Name
79124228 40008c0 4 System.Object[] 0 instance 013b8f8c _items
790fed1c 40008c1 c System.Int32 0 instance 2 _size
790fed1c 40008c2 10 System.Int32 0 instance 2 _version
790f9c18 40008c3 8 System.Object 0 instance 00000000 _syncRoot
79124228 40008c4 1b0 System.Object[] 0 shared static emptyArray
>> Domain:Value 00154598:013b1c2c <<
恩,快要到达目的地了,接着由于里面只有两个Column,我就在Windbg里面全部给输出出来了:
0:000> !dumparray -details 013b8f8c
Name: System.Object[]
MethodTable: 79124228
EEClass: 7912479c
Size: 32(0x20) bytes
Array: Rank 1, Number of elements 4, Type CLASS
Element Methodtable: 790f9c18
[0] 013b82fc
Name: System.Data.DataColumn
MethodTable: 653c3e94
EEClass: 653c3e1c
Size: 148(0x94) bytes
对于每个DataColumn的细节,输出很长,这里就截取一个_items里面的DataColumn对象的细节:
MT Type Value Name
7a745c0c ...ponentModel.ISiteinstance 00000000 site
7a742e54 ....EventHandlerListinstance 00000000 events
790f9c18 System.Object static 00000000 EventDisposed
79104f64 System.Booleaninstance 1 allowNull
79104f64 System.Booleaninstance 0 autoIncrement
790fcb80 System.Int64instance 1 autoIncrementStep
790fcb80 System.Int64instance 0 autoIncrementSeed
790fa3e0 System.Stringinstance 00000000 caption
790fa3e0 System.Stringinstance 013b6070 _columnName
79101058 System.Typeinstance 013b8390 dataType
790f9c18 System.Objectinstance 013b846c defaultValue
653d4c94 System.Int32instance 3 _dateTimeMode
653e63bc ...ta.DataExpressioninstance 00000000 expression
790fed1c System.Int32instance -1 maxLength
790fed1c System.Int32instance 0 _ordinal
79104f64 System.Booleaninstance 0 readOnly
653c75f8 System.Data.Indexinstance 00000000 sortIndex
653c46d8 ...em.Data.DataTableinstance 013b6120 table
79104f64 System.Booleaninstance 0 unique
653d3bfc System.Int32instance 1 columnMapping
790fed1c System.Int32instance 0 _hashCode
790fed1c System.Int32instance 0 errors
79104f64 System.Booleaninstance 0 isSqlType
79104f64 System.Booleaninstance 0 implementsINullable
79104f64 System.Booleaninstance 1 defaultValueIsNull
00000000 instance 00000000 dependentColumns
653d4218 ...ropertyCollectioninstance 00000000 extendedProperties
<