2017-02-10 37 views
0

我在理解MemoryMappedViewStream.PointerOffset屬性時遇到了一些問題。在這個簡單的單元測試中,我期望流的PointerOffset等於500000,但它是41248.流的長度是10000,但至少這是正確的。 _fakeDataPath是一個100萬字節的文件。MemoryMappedViewStream.PointerOffset有錯誤的值

[TestMethod] 
    public void CheckViewHasCorrectOffset() 
    { 
     using (var mmf = MemoryMappedFile.CreateFromFile(_fakeDataPath)) 
     { 
      using (var stream = mmf.CreateViewStream(500000, 10000)) 
      { 
       Assert.AreEqual(500000, stream.PointerOffset); 
      } 
     } 
    } 

單元測試輸出是...

Assert.AreEqual failed. Expected:<500000>. Actual:<41248> 
+0

的[來源](https://referencesource.microsoft.com/#System.Core/System/IO/MemoryMappedFiles/MemoryMappedView.cs,91bd2847a1fb80e7)揭示了這是怎麼回事:'PointerOffset'只是返回傳入到私有'MemoryMappedView'構造函數中的內容,並且它們傳遞給'extraMemNeeded',該方法中的註釋表示:「extraMemNeeded是我們在請求視圖啓動之前分配的額外內存量」,並且是(ulong)offset%(ulong)MemoryMappedFile.GetSystemPageAllocationGranularity();':64k常見:'50 0000%(64 * 1024)= 41248'。可能是一個錯誤。 – Quantic

回答

1

CreateViewStream()是MapViewOfFile() winapi function圍繞.NET包裝。此api最相關的詳細信息是:

高偏移量和低偏移量的組合必須在文件映射中指定偏移量。它們還必須匹配系統的內存分配粒度。也就是說,偏移量必須是分配粒度的倍數。

分配粒度永遠是64K。或者換句話說,本機API要求您指定的偏移量必須始終爲65536的倍數。

這非常痛苦,他們決定在.NET包裝中隱藏該限制。輕鬆完成,他們只需要將一個不同的偏移量傳遞給本地函數,因此它從65536的最小對齊倍數開始,小於500000。並使用不同的內部偏移量,因此您仍然可以獲得有效的500000。因此,您需要修復這樣的代碼:

Assert.AreEqual(500000 % 65536, stream.PointerOffset); 
+0

不應該'PointerOffset'返回'500000 - 500000%65536'而不是?當請求一個500k字節的偏移量時,它必須實際請求64k的倍數,他們將開始到達那裏,所以我認爲實際的偏移量是在[源代碼](https:// referencesource)中顯示的偏移量。 microsoft.com/#System.Core/System/IO/MemoryMappedFiles/MemoryMappedView.cs):'ulong newOffset =(ulong)offset - extraMemNeeded;'。視圖從字節458,752開始,但是「PointerOffset」返回41,248。 – Quantic

+0

不,您認爲newOffset將是PointerOffset的值。它不是,它是extraMemNeeded,請查看MemoryMappedView構造函數調用。 OP的帖子也毫無疑問。 –

+1

我的意思是他們將它設置爲41,248(源代碼中是'extraMemNeeded')的錯誤? ['PointerOffset'](https://msdn.microsoft.com/en-us/library/system.io.memorymappedfiles.memorymappedviewstream.pointeroffset(v = vs.110).aspx):「獲取字節數該視圖的起始位置從內存映射文件的開始處偏移「。視圖從'newOffset'開始,但是他們將'extraMemNeeded'分配給'PointerOffset'。我認爲newOffset *應該*是PointerOffset,並且他們通過傳入extraMemNeeded來搞砸了。 – Quantic