MapViewOfFile引起的问题。。。 (续)
前一遍说到了为什么访问内存会越界,以及我们是如何找到根本原因的。
在知道为什么有越界访问之后,我们下一个问题是:为什么第一次调用mapviewoffile会失败?为什么第二次调用mapviewoffile会成功了?
查阅了msdn一下。如果在调用MapViewOfFile()的时候,dwNumberOfBytesToMap如果大于文件的size,那么该call就会失败,并且error code是access denied。
这个解释貌似和我们发生的很贴切。因为第一次size太大了,第一次就会失败。但是如果第二次我们指明map到文件末尾,那么就会成功。
但是,我们审阅了我们的代码后,觉得不会发生这样的情况。size是根据文件信息读出来的,因而不会有错。
那会是什么引起的了?
因为message会不断的增加,所以message writer会check当前的buffer有没有写完。如果快写完了,那么就flush当前的view,close当前的handle。然后调用createmappingfile(),创建一个更大的MMF。同时为给这块shared memory取一个新的名字。
会不会是message reader这边用错了handle了?
看一下handle的information。
0:000> !handle 0x00000cb0 f
Handle 00000cb0
Type Section
Attributes 0
GrantedAccess 0x4:
None
MapRead
HandleCount 2
PointerCount 4
Name \BaseNamedObjects\3835699D-D3CE-4847-BFCA-A50791DF408D_Log_FileMap10
最后的数字,10,是writer新取的instance number。这个数字很蹊跷,因为应该不会这么大。
看一下实际上应该是多少。
0:000> dt _HeaderLogMessageInfoStruct 0x04dbb6e8+0x05c
MsgMMFReader!_HeaderLogMessageInfoStruct
+0x000 NumberOfRecords : 0x5112
+0x004 WriteNewLogRecordOffset : 0x260070
+0x008 WriteNewRecordIntoBlobOffset : 0x284719
+0x00c SizeOfLogMMFFile : 0x2a0000
+0x010 SizeOfDataMMFFile : 0x2a0000
+0x014 CurrentLogMappingNumberInWriter : 2
+0x018 CurrentBlobMappingNumberInWriter : 1
+0x01c UnreadInfoMsgCnt : 0xfffffe1d
+0x020 UnreadWarningMsgCnt : 0x122b
+0x024 UnreadErrorMsgCnt : 0x21f
+0x028 TotalInfoMsgsCount : 5469
+0x02c TotalWarningMsgsCount : 4651
+0x030 TotalErrorMsgsCount : 853
+0x034 InformationMsgsViewed : 0
+0x035 WarningMsgsViewed : 0
+0x036 ErrorMsgsViewed : 0
+0x038 FirstRecIn24HourWindow : 0x2636
+0x03c FileCreationTimeStamp : _SYSTEMTIME
+0x04c LastTouchTimeStamp : _SYSTEMTIME
我们看到,Writer那边的instance number才是2。而reader那边居然用的是10。这才是导致MapViewOfFIle失败的真正原因。
又重新看了遍code。发现代码那边有check number change scenario。但是,代码是这么写的:
if (m_currentLogMappingNumber < m_msgLogHeaderStruct.CurrentLogMappingNumberInWriter)
{
// remap the mmf
}
这个地方用的是比较大小来决定需不需要重新mapviewoffile。这个才是真真正正的root cause! 应该用“!=”来判断!
把这个地方改为"!="后,这个问题再也没有重现过。