将csv文件放入内存

时间:2011-05-03 04:30:48

标签: .net performance

我有一个非常大(10mb)的csv文件。我解析它并使用通用列表将其放入内存。

我创建了一个代表每一行的类。该类只有几个字段(数据类型为ip-address,string)。

我认为由于文件只有10兆字节,我可以期待内存中的大小相似。

当我发现创建列表的方法是分配300 MB并且没有释放它时,我感到非常惊讶。

这是否正常,以及可能导致这种情况的原因。

请注意,csv文件有很多行(100 000 +),这可能是一个因素。


命名空间Geo     公共类CountryMarker         Public StartAddress As IPAddress         Public EndAddress As IPAddress         公共国家为字符串         Public CountryCode As String     结束班

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

结束命名空间

2 个答案:

答案 0 :(得分:2)

首先,如果文件是ASCII文本或主要是西欧字符(如英语)的UTF-8,那么文本的内存大小至少是磁盘上文件大小的两倍。 .NET将字符串存储为16位Unicode值。因此,例如,“A”在文本文件中占用一个字节,在内存中需要两个字节。

您创建的每个类实例将需要至少24个字节(16个字节的分配,加上8个字节用于引用。)如果您的文件是100,000行,那么最小为2.4 MB。此外,您分配的每个字符串都需要24个字节,以及字符串所需的任何内容。事情加起来很快。

(请注意,我的24字节编号用于64位系统。在32位运行时中,每个分配为16个字节。)

正如其他人所评论的那样,除非你发布一些代码,包括你的班级定义,否则不可能给你更多细节。

至于不释放任何记忆:这很难证明。也许垃圾收集器还没有进行收集。如果它没有看到内存压力(即有足够的可用内存且没有其他进程请求内存),GC可能会认为它不需要收集。

答案 1 :(得分:0)

除了Jim的评论之外,如果您将大量项目读入List,它将在内部以指数级增加的块大小重新分配内存。我不知道确切的启发式,但考虑到.NET中没有realloc - 如果你使用Reflector,你会发现甚至Array.Resize也会分配一个全新的数组。

假设您分配了2049个对象,并假设List在需要更多空间时将缓冲区大小加倍。你将获得1,2,4 ... 1024,2048,最后是4096 - 几乎是你所需要的两倍(这是最糟糕的情况)。

一种解决方案是调用List.TrimExcess()。这将使阵列恢复到合理的大小。更好的解决方案是估计需要存储的项目数,并将其作为初始容量传递给List构造函数。

但是,如果没有看到解析器和类的代码,很难说这会对您的内存使用问题造成多大影响。