💠
F#で関数のメモリ使用量の比較
.NETのGC.GetTotalMemory
を使うことで.NET上のメモリ使用量をバイト単位で参照できます。
open System
let memory = GC.GetTotalMemory false
// val memory: int64 = 94499104L
関数呼び出しの前後で、このメモリ使用量を比較することで関数のメモリ使用量を推測できます。
let before = GC.GetTotalMemory false
f () // 何かしらの関数の呼び出し
let after = GC.GetTotalMemory false
let memory = after - before
// val memory: int64 = バイト単位のメモリ使用量
メモリ使用量を調べる関数をパラメータとして受け取ってメモリ使用量を調べる関数を定義して使い回すことができます。
let measureMemoryUsage (f: unit -> unit) =
let before = GC.GetTotalMemory false
f ()
let after = GC.GetTotalMemory false
after - before
以下は、最大公約数(greatest common divisor)を計算する関数について、逆畳み込み(unfold)を使った計算の関数(gcd
)とループを使った計算の関数(gcd_while
)でメモリ使用量を比較するプログラムです。
open System
let gcd u v =
Seq.unfold
(fun (x, y) ->
if y = 0 then
None
else
Some((x, y), (y, x % y)))
(u, v)
|> Seq.last
|> snd
let gcd_while u v =
let mutable x = u
let mutable y = v
let mutable t = 0
while x > 0 do
if x < y then
t <- x
x <- y
y <- t
x <- x - y
y
let measureMemoryUsage (f: unit -> unit) =
let before = GC.GetTotalMemory(true)
f ()
let after = GC.GetTotalMemory(true)
after - before
let function1 () = printfn "%d" (gcd 461952 116298)
let function2 () = printfn "%d" (gcd_while 461952 116298)
let memoryUsage1 = measureMemoryUsage function1
let memoryUsage2 = measureMemoryUsage function2
printfn "Function 1 used %d bytes" memoryUsage1
printfn "Function 2 used %d bytes" memoryUsage2
18
18
Function 1 used 1184 bytes
Function 2 used 152 bytes
逆畳み込み(unfold)を使った計算の方がメモリ使用量が大きいことがわかります。
Discussion