.net - F# 编译器使死对象保持事件状态

标签 .net f# garbage-collection

我正在实现一些适用于大数据(~250 MB - 1 GB)的算法。为此,我需要一个循环来进行一些基准测试。然而,在这个过程中我了解到 F# 正在做一些令人讨厌的事情,我希望你们中的一些人能够澄清这一点。

这是我的代码(问题描述如下):

open System

for i = 1 to 10 do
    Array2D.zeroCreate 10000 10000 |> ignore    
    printfn "%d" (GC.GetTotalMemory(true)) 

Array2D.zeroCreate 10000 10000 |> ignore
// should force a garbage collection, and GC.Collect() doesn't help either
printfn "%d" (GC.GetTotalMemory(true))
Array2D.zeroCreate 10000 10000 |> ignore    
printfn "%d" (GC.GetTotalMemory(true))
Array2D.zeroCreate 10000 10000 |> ignore    
printfn "%d" (GC.GetTotalMemory(true))
Array2D.zeroCreate 10000 10000 |> ignore    
printfn "%d" (GC.GetTotalMemory(true))

Console.ReadLine() |> ignore

这里的输出将是这样的:

54000
54000
54000
54000
54000
54000
54000
54000
54000
54000
400000000
800000000
1200000000

Out of memory exception

因此,在循环中 F# 会丢弃结果,但是当我不在循环中时,F# 将保留对“死数据”的引用(我已经查看了 IL,显然类 Program 获取了该数据的字段)。为什么?我可以解决这个问题吗?

此代码在 Visual Studio 外部以 Release模式运行。

最佳答案

出现此行为的原因是 F# 编译器在全局范围内的行为与在局部范围内的行为不同。在全局范围内声明的变量将变成静态字段。模块声明是一个静态类,其 let 声明编译为字段/属性/方法。

解决问题的最简单方法是在函数中编写代码:

let main () =    
  Array2D.zeroCreate 10000 10000 |> ignore    
  printfn "%d" (GC.GetTotalMemory(true))
  Array2D.zeroCreate 10000 10000 |> ignore    
  printfn "%d" (GC.GetTotalMemory(true))
  // (...)
  Console.ReadLine() |> ignore

main ()

...但是当您不使用该值并且只是忽略它时,为什么编译器会声明字段呢?这非常有趣 - ignore 函数是一个非常简单的函数,当您使用它时它会被内联。声明为let inlineignore _ = ()。内联函数时,编译器声明一些变量(用于存储函数的参数)。

因此,解决此问题的另一种方法是省略ignore并编写:

Array2D.zeroCreate 10000 10000 
printfn "%d" (GC.GetTotalMemory(true))
Array2D.zeroCreate 10000 10000 
printfn "%d" (GC.GetTotalMemory(true))
// (...)

您会收到一些编译器警告,因为表达式的结果不是 unit,但它会起作用。但是,使用某些函数并在本地范围内编写代码可能更可靠。

关于.net - F# 编译器使死对象保持事件状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6323128/

相关文章:

http - 从 C# 移植到 F# 时出现 System.Net.WebException

syntax - 如何在 F# 中使用 let 创建新的作用域?

python - Cython 指令 no_gc 的用法

java - 如何防止 ParNew 停止应用程序几分钟

c# - AddSingleton - 生命周期 - 类是否需要实现 IDisposable?

.net - 当被不同的 dbContexts 跟踪时,我如何 "supposed"使对象在 WinForms 中保持同步?

c# - C#中的核心类是什么?

.net - 如何使用适用于 .NET 的 AWS 开发工具包将多个文件异步上传到 Amazon S3?

visual-studio-2010 - F# 3.0 是否可用于 Visual Studio 2010 专业版?

c# - Entity Framework 存储过程结果映射