memory-leaksf#idisposablecomputation-expression

Do computations in F# call Dispose() on completion?


I have a database connection with a query similar to as follows in a couple separate files in a project:

SqlTypes.fs

module SqlTypes
open FSharp.Data.TypeProviders

type DBType = SqlDataConnection<ConnectionStrings.DbConnStr>

let getDb() = DBType.GetDataContext() //will this cause a memory leak when called from outside here?

Utilities.fs

module Utilities
open System
open SqlTypes
open System.Linq

///Returns an IQueryable of Orders whose OrderStatus is less than 5 (Not yet released)
let private getOrdersNotYetReleased () =
    let orders = query {
        for order in getDb().Orders do //memleak here?
        where(order.Status < 5)
        sortBy (order.CreatedDateUtc)
        select order
    }
    //return
    orders

Q: Is it necessary to use a use clause (like in the following) to prevent a memory leak?

///Returns an IQueryable of Orders whose OrderStatus is less than 5 (Not yet released)
let private getOrdersNotYetReleased () =
    use db = DBType.GetDataContext() //is this safer? Does it matter if this `use` is here?
    let orders = query {
        for order in db.Orders do 
        where(order.Status < 5)
        sortBy (order.CreatedDateUtc)
        select order
    }
    //return
    orders

Or, will Dispose() be called on the Db object when the computation block exits?


Solution

  • The IDisposable pattern provides for a Dispose() method. The use keyword is there to take advantage of this pattern; if a class implements IDisposable, the author of the class is telling you that using the use keyword with their class is probably a good idea.

    What the Dispose() method actually does depends entirely on what code the author of the class writes for the Dispose() method. There is no guarantee that it even does anything.

    Microsoft's official word on IDisposable has always been that its purpose is to "clean up unmanaged resources," but in practice, Dispose() does whatever the author of the class believes it needs to do to gracefully shut down the object. What it generally does not do is recover memory from managed objects; that is the purpose of the garbage collector.

    But, generally speaking, if a class implements IDisposable, that means it contains a Dispose() method that does something meaningful for the disposition of the object, like closing files or database connections, for example. So. Class implements IDisposable? Use use with it.

    Further Reading
    Managing Resources in F#