F# NativePtr.stackalloc 意外堆栈溢出
F# NativePtr.stackalloc Unexpected Stack Overflow
仍在进行我的 F# 性能测试并尝试使基于堆栈的数组正常工作。有关更多背景信息,请参见此处:.
据我了解,每个函数调用都应该在堆栈中获得自己的帧。然后通过将堆栈指针移回 return 释放此内存。但是下面会导致堆栈溢出错误 - 不确定为什么 stackalloc 是在函数内部执行的。
有趣的是,这只发生在 Release 模式下,而不是 Debug 模式下。
我相信 dotnet 中的标准堆栈大小是 1MB,我没有调整我的。我希望分配 8192 个整数(32768 字节)不会破坏堆栈。
#nowarn "9"
module File1 =
open Microsoft.FSharp.NativeInterop
open System
open System.Diagnostics
let test () =
let stackAlloc x =
let mutable ints:nativeptr<int> = NativePtr.stackalloc x
()
let size = 8192
let reps = 10000
let clock = Stopwatch()
clock.Start()
for i = 1 to reps do
stackAlloc size
let elapsed = clock.Elapsed.TotalMilliseconds
let description = "NativePtr.stackalloc"
Console.WriteLine("{0} ({1} ints, {2} reps): {3:#,##0.####}ms", description, size, reps, elapsed)
[<EntryPoint>]
let main argv =
printfn "%A" argv
test ()
Console.ReadKey() |> ignore
0
更新
按照 Fyodor Soikin 的建议使用 ILSpy 反编译后,我们可以看到在优化过程中发生了内联。有点酷,也有点吓人!
using Microsoft.FSharp.Core;
using System;
using System.Diagnostics;
using System.IO;
[CompilationMapping(SourceConstructFlags.Module)]
public static class File1
{
public unsafe static void test()
{
Stopwatch clock = new Stopwatch();
clock.Start();
for (int i = 1; i < 10001; i++)
{
IntPtr intPtr = stackalloc byte[8192 * sizeof(int)];
}
double elapsed = clock.Elapsed.TotalMilliseconds;
Console.WriteLine("{0} ({1} ints, {2} reps): {3:#,##0.####}ms", "NativePtr.stackalloc", 8192, 10000, elapsed);
}
[EntryPoint]
public static int main(string[] argv)
{
PrintfFormat<FSharpFunc<string[], Unit>, TextWriter, Unit, Unit> format = new PrintfFormat<FSharpFunc<string[], Unit>, TextWriter, Unit, Unit, string[]>("%A");
PrintfModule.PrintFormatLineToTextWriter<FSharpFunc<string[], Unit>>(Console.Out, format).Invoke(argv);
File1.File1.test();
ConsoleKeyInfo consoleKeyInfo = Console.ReadKey();
return 0;
}
}
除此之外,您可能对以下内容感兴趣:
也可以使用属性调整优化:
如果您的 stackAlloc
函数是内联的,就会发生这种情况,从而导致 stackalloc 在 test
的框架内发生。这也解释了为什么它只会发生在 Release 中:内联是一种优化,在 Debug 中比 Release 中执行得少得多。
为了确认这一点,我会尝试使用 ILSpy 查看您生成的代码。
为什么首先需要使用堆栈分配的数组?这看起来与 Donald Knuth 警告我们的事情一模一样。 :-)
仍在进行我的 F# 性能测试并尝试使基于堆栈的数组正常工作。有关更多背景信息,请参见此处:
据我了解,每个函数调用都应该在堆栈中获得自己的帧。然后通过将堆栈指针移回 return 释放此内存。但是下面会导致堆栈溢出错误 - 不确定为什么 stackalloc 是在函数内部执行的。
有趣的是,这只发生在 Release 模式下,而不是 Debug 模式下。
我相信 dotnet 中的标准堆栈大小是 1MB,我没有调整我的。我希望分配 8192 个整数(32768 字节)不会破坏堆栈。
#nowarn "9"
module File1 =
open Microsoft.FSharp.NativeInterop
open System
open System.Diagnostics
let test () =
let stackAlloc x =
let mutable ints:nativeptr<int> = NativePtr.stackalloc x
()
let size = 8192
let reps = 10000
let clock = Stopwatch()
clock.Start()
for i = 1 to reps do
stackAlloc size
let elapsed = clock.Elapsed.TotalMilliseconds
let description = "NativePtr.stackalloc"
Console.WriteLine("{0} ({1} ints, {2} reps): {3:#,##0.####}ms", description, size, reps, elapsed)
[<EntryPoint>]
let main argv =
printfn "%A" argv
test ()
Console.ReadKey() |> ignore
0
更新 按照 Fyodor Soikin 的建议使用 ILSpy 反编译后,我们可以看到在优化过程中发生了内联。有点酷,也有点吓人!
using Microsoft.FSharp.Core;
using System;
using System.Diagnostics;
using System.IO;
[CompilationMapping(SourceConstructFlags.Module)]
public static class File1
{
public unsafe static void test()
{
Stopwatch clock = new Stopwatch();
clock.Start();
for (int i = 1; i < 10001; i++)
{
IntPtr intPtr = stackalloc byte[8192 * sizeof(int)];
}
double elapsed = clock.Elapsed.TotalMilliseconds;
Console.WriteLine("{0} ({1} ints, {2} reps): {3:#,##0.####}ms", "NativePtr.stackalloc", 8192, 10000, elapsed);
}
[EntryPoint]
public static int main(string[] argv)
{
PrintfFormat<FSharpFunc<string[], Unit>, TextWriter, Unit, Unit> format = new PrintfFormat<FSharpFunc<string[], Unit>, TextWriter, Unit, Unit, string[]>("%A");
PrintfModule.PrintFormatLineToTextWriter<FSharpFunc<string[], Unit>>(Console.Out, format).Invoke(argv);
File1.File1.test();
ConsoleKeyInfo consoleKeyInfo = Console.ReadKey();
return 0;
}
}
除此之外,您可能对以下内容感兴趣:
也可以使用属性调整优化:
如果您的 stackAlloc
函数是内联的,就会发生这种情况,从而导致 stackalloc 在 test
的框架内发生。这也解释了为什么它只会发生在 Release 中:内联是一种优化,在 Debug 中比 Release 中执行得少得多。
为了确认这一点,我会尝试使用 ILSpy 查看您生成的代码。
为什么首先需要使用堆栈分配的数组?这看起来与 Donald Knuth 警告我们的事情一模一样。 :-)