2011-05-03 40 views
1

我有一個非常大的(10mb)csv文件。我解析它並使用通用列表將其存入內存。把csv文件放入內存

我創建了一個類來表示每一行。這個類只有幾個字段(數據類型IP地址,字符串)。

我認爲,由於該文件只有10兆字節,我可以預期內存大小相似。

當我發現創建列表的方法是分配300 MB並且沒有釋放它時,我感到非常驚訝。

這是正常的,什麼可以造成這種情況。

請注意,csv文件有很多行(100 000+),這可能是一個因素。


命名空間地理 公共類CountryMarker 公共StartAddress作爲ip地址 公共EndAddress作爲ip地址 公共國家作爲字符串 公共COUNTRYCODE作爲字符串 末級

Public Class Markers 
    Private Const DatabasePath = "~/App_Data/ip.csv" '10 MB file 
    Public Shared List As List(Of CountryMarker) = LoadData() 

    Shared Function LoadData() As List(Of CountryMarker) 
     Dim Markers As New List(Of CountryMarker) 

     Using Stream = New IO.FileStream(Hosting.HostingEnvironment.MapPath(DatabasePath), FileMode.Open) 
      Dim Reader = New StreamReader(Stream) 

      Do While Reader.Peek > -1 
       Dim Line = Reader.ReadLine() 
       Dim Values = Line.Split(",").Select(Function(i) i.Replace("""", "")) 

       Markers.Add(New CountryMarker With {.Country = Values(5), .CountryCode = Values(4), .StartAddress = IPAddress.Parse(Values(0)), .EndAddress = IPAddress.Parse(Values(1))}) 
      Loop 
     End Using 

     Return Markers 
    End Function 
End Class 

末命名空間

+0

你想知道爲什麼會發生這種情況,或提供另一種加載數據的方式? – 2011-05-03 04:32:17

+3

如果我們看到類的定義,這將有所幫助。人們也可能更願意幫助您接受針對您以前的問題的更多答案。 – 2011-05-03 04:33:12

回答

2

第一,如果該文件是ASCII文本或UTF-8主要是西方文件歐洲字符(如英文),那麼文本的內存大小將至少是磁盤上文件大小的兩倍。 .NET將字符串存儲爲16位Unicode值。因此,例如,在文本文件中佔用一個字節的「A」需要兩個字節的內存。

您創建的每個類實例將需要至少24個字節(16個字節的分配,加上8個字節的參考)。如果您的文件是100,000行,那麼最小爲2.4 MB。另外,您分配的每個字符串都需要24個字節,以及字符串所需的任何字符串。事情加起來很快。

(請注意,我的24字節數是64位系統,它的人均分配16個字節的32位運行。)

正如其他人評論說,這是不可能給你任何更多的細節,除非你發佈了一些代碼,包括你的類定義。

至於沒有釋放任何記憶:這是很難證明。也許垃圾收集器還沒有到處做集合呢。如果它沒有看到內存壓力(即有足夠的內存可用,並且沒有其他進程在尋求內存),GC可能會認爲它不需要收集。

0

除了Jim的評論之外,如果您將很多項目讀入列表中,它將以指數級增加的塊大小內部重新分配內存。我不知道確切的啓發式,但考慮到.NET中沒有realloc - 如果您使用Reflector,您會看到即使Array.Resize也會分配一個全新的數組。

假設您分配了2049個對象,並且假設List在需要更多空間時會將緩衝區大小加倍。你會得到1,2,4,1024,2048,最後是4096 - 幾乎是你要求的兩倍(這是最糟糕的情況)。

一個解決方案是調用List.TrimExcess()。這將使陣列回落到合理的大小。一個更好的解決方案是估計需要存儲的項目數量,並將其作爲List構造函數的初始容量傳遞。

但是,沒有看到解析器和類的代碼,很難說這對您的內存使用問題有多大影響。

+0

只需要添加一下,如果垃圾收集器暫時不運行,您可以在一段時間內看到約需要的使用量的3倍。這是因爲2048,1024,512 ... 4,2,1緩衝區仍在等待收集。但是,當GC啓動時,這應該自行糾正。 – 2011-05-03 07:33:01

+0

即使調整了多餘的空間,列表本身的大小也將佔用比所有「行對象」更少的空間。 – 2011-05-03 08:26:52

+0

我同意,但有幾個數據可以在那裏輕鬆採摘。供應產能的成本非常低。 – 2011-05-03 15:31:52