我想向同事证明你可以分配超过2GB的内存,所以我做了一个小测试应用程序。
let mega = 1 <<< 20
let konst x y = x
let allocate1MB _ = Array.init mega (konst 0uy)
let memoryHog = Array.Parallel.init 8192 allocate1MB
printfn "I'm done..."
System.Console.ReadKey() |> ignore
这有效,你实际上看到这个过程正在愉快地占据系统的记忆。但是,它需要一些时间 - 因此Array.Parallel.init
。
我注意到,如果我用
写它,相同的代码不起作用let allocate1MB _ = Array.zeroCreate mega
更准确地说,没有分配数据,也没有时间。
因此,我的问题; Array.zeroCreate和Array.init之间的语义有什么不同?
我知道Array.init
每次都会运行konst 0uy
函数,这可以解释时差。但为什么Array.zeroCreate
没有分配内存?
答案 0 :(得分:2)
来自FSharp.Core来源:
let inline init (count:int) (f: int -> 'T) =
if count < 0 then invalidArg "count" InputMustBeNonNegativeString
let arr = (zeroCreateUnchecked count : 'T array)
for i = 0 to count - 1 do
arr.[i] <- f i
arr
let zeroCreate count =
if count < 0 then invalidArg "count" (SR.GetString(SR.inputMustBeNonNegative))
Microsoft.FSharp.Primitives.Basics.Array.zeroCreateUnchecked count
let inline zeroCreateUnchecked (count:int) =
(# "newarr !0" type ('T) count : 'T array #)
正如您所看到的,这两个函数在引擎盖下使用zeroCreateUnchecked
,它被编译为newarr
IL,它应该将新数组推送到堆栈中。
在您的情况下,这不消耗任何内存的事实可能表明某种优化是负责任的。我认为JIT或编译器正在删除此操作,因为从未使用过创建的数组,并且在Array.init
的情况下显然不会发生。
答案 1 :(得分:0)
Array.zeroCreate
确实会分配内存,它会创建数组,每个项目都初始化为默认值,而Array.init
则可以设置每个项目的值。
e.g。
// create large array of bytes set to 0
let array : byte[] = Array.zeroCreate (1 <<< 20)
// create large array of object references set to null.
let array : obj[] = Array.zeroCreate (1 <<< 20)
更改示例中的这两行将在运行时抛出Out of Memory异常,因此正在分配内存。
let allocate1MB _ = Array.zeroCreate mega
let memoryHog : byte[][] = Array.Parallel.init 8192 allocate1MB
答案 2 :(得分:0)
回答你的直接问题:Array.zeroCreate
生成类型为默认值的元素数组,而Array.init
使用提供的生成器函数创建每个元素数组。您始终可以使用Array.zeroCreate
的对应生成器函数来实现Array.init
的语义:
- 对于值类型,例如byte
:
> let az: byte [] = Array.zeroCreate 1;;
val az : byte [] = [|0uy|]
> let ai = Array.init 1 (fun _ -> 0uy);;
val ai : byte [] = [|0uy|]
- 用于参考类型,例如string
:
> let az: string [] = Array.zeroCreate 1;;
val az : string [] = [|null|]
> let ai = Array.init 1 (fun _ -> Unchecked.defaultof<string>);;
val ai : string [] = [|null|]
现在,将此观察应用于分配超过2GB RAM的原始问题,您可以在enabling gcAllowVeryLargeObjects
in configuration {{{3}}之后使用.NET 4.5和64位操作系统下的Array.zeroCreate
进行此类分配。 1}}。下面的单行代码可以立即为fsiAnyCPU.exe
的数组分配 8GB 的RAM :
int
以下证明这有效:
> let bigOne: int [] = Array.zeroCreate 2146435071