0

The following is an MWE that illustrates my problem:

let f (n : int) : unit =
    {1 .. n}
    |> Seq.iter (fun s ->
        // Do something memory intensive, without retaining anything
        ()
        )
    ()

// First call
f 100

// Second call
{1 .. 10}
|> Seq.iter (fun s -> f 10)

Even though the end result of the two calls is the same, the first call performs much worse than the second call. The memory usage in the first call goes up to 95%, and the system slows down to a crawl. The memory usage of the second one never exceeds 50%.

Can someone please explain why, and how I should have foreseen it? Thanks in advance for your help.

Shredderroy
  • 2,860
  • 2
  • 29
  • 53
  • 1
    This is the .Net JIT - the first time the code is run it runs under an interpreter. Running subsequently, the code is compiled to machine code and is much faster. As a result, for .Net performance benchmarks, you always run the code once before timing. – John Palmer Dec 11 '12 at 03:14
  • Even though I wrote up the MWE as I did, the actual code does not have one type of call followed immediately by the other type. I compiled the project, and did run each type of call more than once. Each time, the memory consumption for the first type of call skyrocketed. – Shredderroy Dec 11 '12 at 03:24
  • I believe that the problem has to do with the fact that in the first type the CLR does not attempt to free the memory until all the iterations have been completed in `f`. In the second call, memory is probably freed after each call to `f` from the outer sequence. This is a bit counterintuitive, since I expect the system to figure out that `f` is not retaining anything, and so to free memory as necessary. – Shredderroy Dec 11 '12 at 03:26
  • 2
    Can you provide a reproducible example? How much memory did you allocate in an iteration with s=100 or s=10? How much memory is available in the system? If the system runs out of memory around s=100, the behavior is normal. – pad Dec 11 '12 at 04:22
  • 3
    I tried out your code with reading a large file into memory on iter. It seems to get GC'd perfectly fine in both cases. The generated IL for both cases also seem the same. – Asti Dec 11 '12 at 05:03

0 Answers0