我正在为一种小语言做一个解释器,用于像kdb+中那样进行数组/关系编程。
我想知道当一个值被编码在AGDT中时,F#增加了多少内存:
type value =
| Dec of int
| Num of int array
| Float of float array
| Array of value
| Arr of value array
let print x =
printfn "%A" x
let a = [|1; 2|]
let b = Num(a)
let c = [| Dec(1); Dec(2) |]
//print (sizeof Arr) Don't have a easy way to do this
我想知道在F#中,a、b、c的性能是否相同。其思想是解释器需要主要处理数组。
因为看起来(根据我在SO中的搜索).NET没有直接的方法来检查值的内存大小,所以我在swift中做了类似的事情:
indirect enum ExprC {
case IntC(x:Int32)
case IntA(x:Array<Int32>)
case ArrayC(x:Array<ExprC>)
}
let values:[Int32] = [1, 2]
let v1 = ExprC.ArrayC(x: [ExprC.IntC(x:1), ExprC.IntC(x: 2)])
let v2 = ExprC.IntA(x: values)
print(sizeofValue(values))
print(sizeofValue(v1))
print(sizeofValue(v2))
//RESULTS
//8
//8
//8
顺便说一句,这个结果出乎我的意料,我想编码必须有额外的存储成本,所以我不确定F#中是否会发生这种情况。
public class value {
public class Dec : value { public int Item { get; } }
public class Num : value { public int[] Item { get; } }
public class Float : value { public double[] Item { get; } }
public class Array : value { public value Item { get; } }
public class Arr : value { public value[] Item { get; } }
}
除此之外,这真的很难说,因为类的分配方式可能会随着VM实现和底层机器体系结构的不同而不同。例如,在x86/x64上的Windows上的完整.NET FW上,对象将有一个32或64位的对象标头,加上对象的任何内容,可能是对齐的(查看本文了解一些详细信息)。这意味着,例如,您的Dec
大小写将占用8或12个字节。
然而,其他VM实现可能会做不同的事情。CoreCLR、Mono、MicroFW、.NET CF——所有这些都可能对对象分配有自己的看法,而.NET Native编译器甚至可能完全优化整个过程。
这就是为什么.NET一般不能告诉你类的"大小":一般来说,它不知道。仔细想想,谈论"尺寸"可能并不总是有意义的。Swift可以逃脱惩罚,因为它没有一个开放的标准虚拟机,所以它可以随心所欲。
如果你真的需要保证一个特定的内存布局,.NET确实有这样的功能(查找StructLayoutAttribute),但它不适用于ADT,这是可以理解的。
最后,我觉得你可能在误导你的注意力。你为什么想知道这些事情?如果你真的很关心内存占用,你根本不应该使用F#(或Swift),你应该使用C(或者,如果你真喜欢函数式编程,请查看Rust)。否则,请记住"过早优化"。