.net 优化查询以提高内存使用率:OutOfMemory异常

.net 优化查询以提高内存使用率:OutOfMemory异常,.net,f#,.net,F#,我有一个控制台应用程序,可以连接到远程数据库并运行多个查询 我正在使用64位F#构建应用程序。我对这条路充满信心 C:\Program Files (x86)\Microsoft SDKs\F#\4.0\Framework\v4.0\fsc.exe 在构建过程中用作F#框架路径。此外,上面的文件路径位于my path环境变量中 每个查询的结构如下: query{expression} |> Seq.toArray |> Array.map (fun q -> {a = q.

我有一个控制台应用程序,可以连接到远程数据库并运行多个查询

我正在使用64位F#构建应用程序。我对这条路充满信心

C:\Program Files (x86)\Microsoft SDKs\F#\4.0\Framework\v4.0\fsc.exe 
在构建过程中用作F#框架路径。此外,上面的文件路径位于my path环境变量中

每个查询的结构如下:

query{expression}
|> Seq.toArray
|> Array.map (fun q -> {a = q.a; 
                        b = q.b; 
                        etc...}
|> writeToJson ("filePath")
当这些查询结果在应用程序的下游使用时,我写入一个
JSON
文件

我在查询中使用了
Array
s,正如我所包含的那样

<runtime>
 <gcAllowVeryLargeObjects enabled="true" />
</runtime>
返回约250万个结果。我将查询结果传送到的
sizeof
8


有人知道如何防止OOM异常发生吗?在
gcAllowVeryLargeObjects
和使用F#64位之间,我本以为可以解决这个问题。

基本上,您的应用程序必须进行调试,如果不访问数据库和您的环境,这将很困难

仅仅因为你调用fsc并不意味着它是64位的(尽管通常是)。编译器的各种标志通常通过Visual Studio在
.fsproj
文件中设置,但您当然可以手动编辑它

例如,我可以创建一个32位的配置文件:

true
或:
x64
bin\Release\ConsoleApplication8.XML
错误

您可以在FSIAnyCpu.exe中开始测试,它是FSI的64位版本(应该是VSCode上的默认值,可以在VS2015中设置)

  • 然后,您应该确保可以直接在SQL中在服务器上运行查询

  • 作为下一步,我假设您正在使用某种类型提供程序来访问数据库,请确保连接已清理。例如,为每个查询使用单独的datacontext,并将其与
    use
    notlet绑定,这样它将被释放,GC将清理。对于某些数据库,您可以禁用对象跟踪,因为您正在从数据库中读取数据,所以这应该无关紧要

  • 正如评论中提到的,尝试使用
    Seq

  • 最后,当您转换为JSON时,尝试使用某种StreamWriter,这样它就不会阻塞

  • 但最终,您必须通过仔细测试(阅读添加一些sleep和print语句…)并在任务管理器上查看内存来隔离导致内存不足异常的代码段。当然,最好使用Performance Profiler is VS2015或其他类似Redgate的.NET Profiler的工具

    作为初学者,您需要在查询(或其中一个查询)或Json导出器中找到异常的原因

    添加1:

    这个小片段将为您提供一个8GB的阵列—没有问题。所以你可以用它来测试。数组长度仍然有一个限制,每个维度大约有20亿个元素

    open System
    
    [<EntryPoint>]
    let main argv =
    
        let x = Int32.MaxValue /2 
        printfn "%A" x 
        let big = Array.init x (fun _ -> "aa") 
        Console.ReadLine() |> ignore
        printfn "%A" big.Length
    
        0 
    
    开放系统
    []
    让主argv=
    设x=Int32.MaxValue/2
    printfn“%A”x
    让big=Array.init x(fun->“aa”)
    Console.ReadLine()|>忽略
    printfn“%A”大。长度
    0
    
    我会尽量避免使用数组。它应该会有所帮助,因为seq是懒散的,将所有内容都保留为
    seq
    并没有改变查询或OOM异常的行为。顺便说一句,我不确定64位可以寻址多少空间,但这是TB范围。若您的进程是32位的,但在3GB左右可能会遇到麻烦。可能是内存泄漏?对象的
    大小也不能测量对象占用的实际内存。这将是8字节x2.5M=约20MB,实际上是填充int或字符串的2.5M元素数组的大小。从外观上看,您返回的任何内容都要大得多。哦,因此,尽管
    大小有限,但我还是先从最简单的解决方案开始:我将
    writeToJson
    函数改为,而不是一次性将整件事写入流。虽然运行所有查询的过程需要>1小时,但我同意这一点。这是最多每月运行一次的功能。
    open System
    
    [<EntryPoint>]
    let main argv =
    
        let x = Int32.MaxValue /2 
        printfn "%A" x 
        let big = Array.init x (fun _ -> "aa") 
        Console.ReadLine() |> ignore
        printfn "%A" big.Length
    
        0