"using" vs "= null" and object lifetime

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • MuZZy

    "using" vs "= null" and object lifetime

    Hi,

    Lately i've been (and still am) fixing some memory leaks problems in the project i just took over
    when i got this new job. Among the other issues i've noticed that for localy created objects it
    makes difference to explicitly put them to null after working with them is done - it somehow makes
    the GC collect them sooner, like here:

    void SomeFunc()
    {
    MyClass c = new MyClass();
    c.CallSomeOther Func();
    c = null;
    }

    If i don't put "c" to null time to get it collected is way longer than if i explicitly dereference
    the object. It's really strange, as it's obvoius that object's lifetime is limited by body of
    "SomeFunc". But anyway, my question is: is there any difference in the first example compared to this:

    void SomeFunc()
    {
    using (MyClass c = new MyClass())
    {
    c.CallSomeOther Func();
    }
    }

    The second way looks nicer for me and avoids forgetting to explicitly dereference the object,
    but i'm not sure if this second case is being treated the same way as the first one.

    Any suggestions/ideas would be highly appreciated!

    Thnak you,
    Andrey
  • Tom Porterfield

    #2
    Re: "using&quo t; vs "= null" and object lifetime

    On Thu, 17 Feb 2005 10:02:52 -0500, MuZZy wrote:
    [color=blue]
    > Lately i've been (and still am) fixing some memory leaks problems in the project i just took over
    > when i got this new job. Among the other issues i've noticed that for localy created objects it
    > makes difference to explicitly put them to null after working with them is done - it somehow makes
    > the GC collect them sooner, like here:
    >
    > void SomeFunc()
    > {
    > MyClass c = new MyClass();
    > c.CallSomeOther Func();
    > c = null;
    > }
    >
    > If i don't put "c" to null time to get it collected is way longer than if i explicitly dereference
    > the object. It's really strange, as it's obvoius that object's lifetime is limited by body of
    > "SomeFunc". But anyway, my question is: is there any difference in the first example compared to this:
    >
    > void SomeFunc()
    > {
    > using (MyClass c = new MyClass())
    > {
    > c.CallSomeOther Func();
    > }
    > }
    >
    > The second way looks nicer for me and avoids forgetting to explicitly dereference the object,
    > but i'm not sure if this second case is being treated the same way as the first one.[/color]

    Your second case is not the same as the first. Another way to write the
    second would be:

    void SomeFunc()
    {
    MyClass c = new MyClass()
    try
    {
    c.CallSomeOther Func();
    }
    finally
    {
    c.Dispose();
    }
    }

    So in your first example you are setting c to null before it goes out of
    scope. In your second example you are not setting c to null, but you are
    guaranteeing that c.Dispose() will be called no matter what happens.
    --
    Tom Porterfield

    Comment

    • Nicholas Paldino [.NET/C# MVP]

      #3
      Re: "using&quo t; vs "= null" and object lifetime

      Andrey,

      See inline:[color=blue]
      > Lately i've been (and still am) fixing some memory leaks problems in the
      > project i just took over when i got this new job. Among the other issues
      > i've noticed that for localy created objects it makes difference to
      > explicitly put them to null after working with them is done - it somehow
      > makes the GC collect them sooner, like here:
      >
      > void SomeFunc()
      > {
      > MyClass c = new MyClass();
      > c.CallSomeOther Func();
      > c = null;
      > }[/color]

      This depends on how it is compiled. If you are compiling in debug mode,
      then yes, it will make it GC faster (although how much faster is
      questionable since c would have been released very quickly afterwards, due
      to exiting the method). The reason for this is that code compiled in debug
      mode will not have references released when they are no longer used. When
      compiled for release mode, however, you are actually ^extending^ the
      lifetime of your object with the "c = null" assignment. If the statement
      was not there, the compiler would realize that the object pointed to by c is
      no longer needed after the call to CallSomeOtherFu nc (unless the reference
      pointed to by c is stored somewhere else in the call to CallSomeOtherFu nc),
      and then set it to null, allowing it to become eligible for GC.

      However, with the "c = null" statement, the compiler realizes (although
      I don't know if agressive optimizations here can pick it up) that it is
      needed for another call, and the object pointed to by c isn't made eligible
      until ^after^ the assignment.
      [color=blue]
      > If i don't put "c" to null time to get it collected is way longer than if
      > i explicitly dereference the object. It's really strange, as it's obvoius
      > that object's lifetime is limited by body of "SomeFunc".[/color]

      This isn't true. GCs are not pre-determined. Why a GC occurs very
      quickly in one run of the app as opposed to very late in another run of the
      app is not easily determinable. There are other factors outside your
      application which can force a GC as well. The timing of one GC in one run
      of the app vs a GC of another run in an app means very little.
      [color=blue]
      > But anyway, my question is: is there any difference in the first example
      > compared to this:
      >
      > void SomeFunc()
      > {
      > using (MyClass c = new MyClass())
      > {
      > c.CallSomeOther Func();
      > }
      > }
      >
      > The second way looks nicer for me and avoids forgetting to explicitly
      > dereference the object,
      > but i'm not sure if this second case is being treated the same way as the
      > first one.[/color]

      This is a separate issue completely. Just because you implement
      IDispose, it doesn't mean that the object doesn't need to be GCed anymore.
      If you have IDispose, it means that you need to manage the lifetime of the
      object in some way by calling the Dispose method on the implementation of
      IDispose. There are usually two reasons you implement IDispose.

      The first, and most common, is because the instance is holding on to
      some unmanaged resource, and you need to release it as soon as possible.
      When implementing IDispose in this scenario, you also need to implement a
      finalizer (destructor, although the term is incorrect, IMO). The finalizer
      is meant to be a safeguard if people don't call Dispose. It will basically
      release the unmanaged resource if it hasn't been done already.

      Finalization is an expensive process. The object is basically
      ressurected and placed in a finalization queue, and then has the finalizer
      executed. If Dispose is called on an object, it doesn't need to be
      finalized, which is why you see a call to GC.SuppressFina lize in the
      implementation of Dispose, and not the finalizer itself. Since the
      finalizer and Dispose do the same thing, if Dispose is called, you can
      effectively tell the GC to not finalize you, and avoid that costly overhead.

      However, even if you say that you are going to suppress finalization,
      the object still has to be GCed. The process of having the memory reclaimed
      still has to occur on this object, even when Dispose is called. However,
      it's something you really don't care about, because it's just memory, and
      you gave up control of that (for the most part) by agreeing to run in the
      CLR (that's the purpose of the GC, to worry about these things, not yours).

      Suppressing finalization only means the finalizer will not be called, it
      doesn't mean that the object has been GCed.

      The second reason to use IDispose is because you need some deterministic
      finalization to take place. For example, you might always need some
      variable set back after an operation in a method. In this case generating a
      class which implements IDisposable might be a good idea, since you can
      revert the variable back when the using block is exited (instead of having
      to explicitly remembering to code a try/catch/finally block).

      In your case, you fall into the first category for using IDispose.
      Using the using statement will be important, if you actually have an
      unmanaged resource you are holding on to. If you do not, and it is just a
      regular class, then using the using statement will not work, and
      implementing IDispose will not help either.

      Hope this helps.

      --
      - Nicholas Paldino [.NET/C# MVP]
      - mvp@spam.guard. caspershouse.co m
      [color=blue]
      >
      > Any suggestions/ideas would be highly appreciated!
      >
      > Thnak you,
      > Andrey[/color]


      Comment

      • MuZZy

        #4
        Re: "using&quo t; vs "= null" and object lifetime

        Tom Porterfield wrote:[color=blue]
        > On Thu, 17 Feb 2005 10:02:52 -0500, MuZZy wrote:
        >
        >[color=green]
        >>Lately i've been (and still am) fixing some memory leaks problems in the project i just took over
        >>when i got this new job. Among the other issues i've noticed that for localy created objects it
        >>makes difference to explicitly put them to null after working with them is done - it somehow makes
        >>the GC collect them sooner, like here:
        >>
        >>void SomeFunc()
        >>{
        >> MyClass c = new MyClass();
        >> c.CallSomeOther Func();
        >> c = null;
        >>}
        >>
        >>If i don't put "c" to null time to get it collected is way longer than if i explicitly dereference
        >>the object. It's really strange, as it's obvoius that object's lifetime is limited by body of
        >>"SomeFunc". But anyway, my question is: is there any difference in the first example compared to this:
        >>
        >>void SomeFunc()
        >>{
        >> using (MyClass c = new MyClass())
        >> {
        >> c.CallSomeOther Func();
        >> }
        >>}
        >>
        >>The second way looks nicer for me and avoids forgetting to explicitly dereference the object,
        >>but i'm not sure if this second case is being treated the same way as the first one.[/color]
        >
        >
        > Your second case is not the same as the first. Another way to write the
        > second would be:
        >
        > void SomeFunc()
        > {
        > MyClass c = new MyClass()
        > try
        > {
        > c.CallSomeOther Func();
        > }
        > finally
        > {
        > c.Dispose();
        > }
        > }
        >
        > So in your first example you are setting c to null before it goes out of
        > scope. In your second example you are not setting c to null, but you are
        > guaranteeing that c.Dispose() will be called no matter what happens.[/color]

        Thank you!
        So if i'm more concerned about shorter object lifetime, i'd rather do this:

        void SomeFunc()
        {
        MyClass c = new MyClass()
        c.CallSomeOther Func();
        c.Dispose();
        c = null;
        }

        than use "using"?
        Right?

        Comment

        • Sherif ElMetainy

          #5
          Re: "using&quo t; vs "= null" and object lifetime

          Hello

          In a Debug build, the object will not be eligible for garbage collection
          until the function returns or you set the object reference to null. In a
          Release build, the JIT compiler makes some optimizations, so that the
          variable is eligible for garbage collection as soon as it is no longer
          needed, even if the function call is still active. So in a release build you
          don't need to set the object reference to null after you finish using it
          because CLR and JIT will take care of that.

          As for the using statement, its use is not to make GC collect the memory for
          the object. It is used so that any resource (such as db connections, file
          handles, GDI object, native memory, etc) held by the object is released
          soon, even if the GC collects it at a later time. It can be used only with
          objects that implement IDisposable, and it makes sure that the Dispose
          method gets called after you finish using the object.

          Best regards,
          Sherif

          "MuZZy" <leyandrew@yaho o.com> wrote in message
          news:HsudnRt82M iFL4nfRVn-1A@comcast.com. ..[color=blue]
          > Hi,
          >
          > Lately i've been (and still am) fixing some memory leaks problems in the[/color]
          project i just took over[color=blue]
          > when i got this new job. Among the other issues i've noticed that for[/color]
          localy created objects it[color=blue]
          > makes difference to explicitly put them to null after working with them is[/color]
          done - it somehow makes[color=blue]
          > the GC collect them sooner, like here:
          >
          > void SomeFunc()
          > {
          > MyClass c = new MyClass();
          > c.CallSomeOther Func();
          > c = null;
          > }
          >
          > If i don't put "c" to null time to get it collected is way longer than if[/color]
          i explicitly dereference[color=blue]
          > the object. It's really strange, as it's obvoius that object's lifetime is[/color]
          limited by body of[color=blue]
          > "SomeFunc". But anyway, my question is: is there any difference in the[/color]
          first example compared to this:[color=blue]
          >
          > void SomeFunc()
          > {
          > using (MyClass c = new MyClass())
          > {
          > c.CallSomeOther Func();
          > }
          > }
          >
          > The second way looks nicer for me and avoids forgetting to explicitly[/color]
          dereference the object,[color=blue]
          > but i'm not sure if this second case is being treated the same way as the[/color]
          first one.[color=blue]
          >
          > Any suggestions/ideas would be highly appreciated!
          >
          > Thnak you,
          > Andrey[/color]


          Comment

          • MuZZy

            #6
            Re: &quot;using&quo t; vs &quot;= null&quot; and object lifetime

            Thanks guys, now it's more clear for me!
            MOst important things you've told are that it makes sence to use "using" only if object has
            IDisposable interface, and second, that debug mode slighty differs from Release mode in terms of
            memory management - i shouldn't explcitly dereference objects in Release mode.

            MuZZy wrote:[color=blue]
            > Hi,
            >
            > Lately i've been (and still am) fixing some memory leaks problems in the
            > project i just took over when i got this new job. Among the other issues
            > i've noticed that for localy created objects it makes difference to
            > explicitly put them to null after working with them is done - it somehow
            > makes the GC collect them sooner, like here:
            >
            > void SomeFunc()
            > {
            > MyClass c = new MyClass();
            > c.CallSomeOther Func();
            > c = null;
            > }
            >
            > If i don't put "c" to null time to get it collected is way longer than
            > if i explicitly dereference the object. It's really strange, as it's
            > obvoius that object's lifetime is limited by body of "SomeFunc". But
            > anyway, my question is: is there any difference in the first example
            > compared to this:
            >
            > void SomeFunc()
            > {
            > using (MyClass c = new MyClass())
            > {
            > c.CallSomeOther Func();
            > }
            > }
            >
            > The second way looks nicer for me and avoids forgetting to explicitly
            > dereference the object,
            > but i'm not sure if this second case is being treated the same way as
            > the first one.
            >
            > Any suggestions/ideas would be highly appreciated!
            >
            > Thnak you,
            > Andrey[/color]

            Comment

            • Tom Porterfield

              #7
              Re: &quot;using&quo t; vs &quot;= null&quot; and object lifetime

              On Thu, 17 Feb 2005 10:24:18 -0500, MuZZy wrote:
              [color=blue]
              > So if i'm more concerned about shorter object lifetime, i'd rather do this:
              >
              > void SomeFunc()
              > {
              > MyClass c = new MyClass()
              > c.CallSomeOther Func();
              > c.Dispose();
              > c = null;
              > }
              >
              > than use "using"?
              > Right?[/color]

              No, see Nicholas' reply on why this doesn't guarantee a shorter object
              lifetime, and in fact might lengthen it.
              --
              Tom Porterfield

              Comment

              • Jon Skeet [C# MVP]

                #8
                Re: &quot;using&quo t; vs &quot;= null&quot; and object lifetime

                MuZZy <leyandrew@yaho o.com> wrote:[color=blue]
                > Lately i've been (and still am) fixing some memory leaks problems in
                > the project i just took over when i got this new job. Among the other
                > issues i've noticed that for localy created objects it makes
                > difference to explicitly put them to null after working with them is
                > done - it somehow makes the GC collect them sooner, like here:
                >
                > void SomeFunc()
                > {
                > MyClass c = new MyClass();
                > c.CallSomeOther Func();
                > c = null;
                > }
                >
                > If i don't put "c" to null time to get it collected is way longer
                > than if i explicitly dereference the object.[/color]

                In release, or only in debug? I'd be very surprised if it made any
                difference in release mode.

                --
                Jon Skeet - <skeet@pobox.co m>
                Pobox has been discontinued as a separate service, and all existing customers moved to the Fastmail platform.

                If replying to the group, please do not mail me too

                Comment

                • Jon Skeet [C# MVP]

                  #9
                  Re: &quot;using&quo t; vs &quot;= null&quot; and object lifetime

                  Nicholas Paldino [.NET/C# MVP] <mvp@spam.guard .caspershouse.c om> wrote:[color=blue][color=green]
                  > > void SomeFunc()
                  > > {
                  > > MyClass c = new MyClass();
                  > > c.CallSomeOther Func();
                  > > c = null;
                  > > }[/color]
                  >
                  > This depends on how it is compiled. If you are compiling in debug mode,
                  > then yes, it will make it GC faster (although how much faster is
                  > questionable since c would have been released very quickly afterwards, due
                  > to exiting the method). The reason for this is that code compiled in debug
                  > mode will not have references released when they are no longer used.[/color]

                  Are you sure it's a case of how it's compiled? I was under the
                  impression that it was how it was being *run* - which would make sense,
                  as if you're not running in the debugger, you don't need to know the
                  value of c after the last use even if the debug symbols are present.

                  When I get the chance I may test this in each configuration just to see
                  what happens...

                  --
                  Jon Skeet - <skeet@pobox.co m>
                  Pobox has been discontinued as a separate service, and all existing customers moved to the Fastmail platform.

                  If replying to the group, please do not mail me too

                  Comment

                  • Sean Hederman

                    #10
                    Re: &quot;using&quo t; vs &quot;= null&quot; and object lifetime

                    "MuZZy" <leyandrew@yaho o.com> wrote in message
                    news:fsmdnTNu1c faI4nfRVn-og@comcast.com. ..[color=blue]
                    > Thanks guys, now it's more clear for me!
                    > MOst important things you've told are that it makes sence to use "using"
                    > only if object has IDisposable interface, and second, that debug mode
                    > slighty differs from Release mode in terms of memory management - i
                    > shouldn't explcitly dereference objects in Release mode.[/color]

                    Don't confine that last statement to just Release mode. There's no real need
                    to dereference objects in almost all circumstances.
                    [color=blue]
                    >
                    > MuZZy wrote:[color=green]
                    >> Hi,
                    >>
                    >> Lately i've been (and still am) fixing some memory leaks problems in the
                    >> project i just took over when i got this new job. Among the other issues
                    >> i've noticed that for localy created objects it makes difference to
                    >> explicitly put them to null after working with them is done - it somehow
                    >> makes the GC collect them sooner, like here:
                    >>
                    >> void SomeFunc()
                    >> {
                    >> MyClass c = new MyClass();
                    >> c.CallSomeOther Func();
                    >> c = null;
                    >> }
                    >>
                    >> If i don't put "c" to null time to get it collected is way longer than if
                    >> i explicitly dereference the object. It's really strange, as it's obvoius
                    >> that object's lifetime is limited by body of "SomeFunc". But anyway, my
                    >> question is: is there any difference in the first example compared to
                    >> this:
                    >>
                    >> void SomeFunc()
                    >> {
                    >> using (MyClass c = new MyClass())
                    >> {
                    >> c.CallSomeOther Func();
                    >> }
                    >> }
                    >>
                    >> The second way looks nicer for me and avoids forgetting to explicitly
                    >> dereference the object,
                    >> but i'm not sure if this second case is being treated the same way as the
                    >> first one.
                    >>
                    >> Any suggestions/ideas would be highly appreciated!
                    >>
                    >> Thnak you,
                    >> Andrey[/color][/color]


                    Comment

                    • MuZZy

                      #11
                      Re: &quot;using&quo t; vs &quot;= null&quot; and object lifetime

                      Jon Skeet [C# MVP] wrote:[color=blue]
                      > MuZZy <leyandrew@yaho o.com> wrote:
                      >[color=green]
                      >>Lately i've been (and still am) fixing some memory leaks problems in
                      >>the project i just took over when i got this new job. Among the other
                      >>issues i've noticed that for localy created objects it makes
                      >>difference to explicitly put them to null after working with them is
                      >>done - it somehow makes the GC collect them sooner, like here:
                      >>
                      >>void SomeFunc()
                      >>{
                      >> MyClass c = new MyClass();
                      >> c.CallSomeOther Func();
                      >> c = null;
                      >>}
                      >>
                      >>If i don't put "c" to null time to get it collected is way longer
                      >>than if i explicitly dereference the object.[/color]
                      >
                      >
                      > In release, or only in debug? I'd be very surprised if it made any
                      > difference in release mode.
                      >[/color]

                      I haven't tested that in Release mode - just Debug.
                      Now having read all the responces i fnally got the whole picture i hope:)

                      Comment

                      • Ollie Riches

                        #12
                        Re: &quot;using&quo t; vs &quot;= null&quot; and object lifetime

                        Surely assigning an object to null at the end of a method will be optimized
                        out during compilation?

                        Or am I trying to second guess what goes on during compliation :)

                        Ollie


                        But there again how can I second guess what the compile or
                        "Jon Skeet [C# MVP]" <skeet@pobox.co m> wrote in message
                        news:MPG.1c7eec 7c445711f198bd6 0@msnews.micros oft.com...[color=blue]
                        > Nicholas Paldino [.NET/C# MVP] <mvp@spam.guard .caspershouse.c om> wrote:[color=green][color=darkred]
                        >> > void SomeFunc()
                        >> > {
                        >> > MyClass c = new MyClass();
                        >> > c.CallSomeOther Func();
                        >> > c = null;
                        >> > }[/color]
                        >>
                        >> This depends on how it is compiled. If you are compiling in debug
                        >> mode,
                        >> then yes, it will make it GC faster (although how much faster is
                        >> questionable since c would have been released very quickly afterwards,
                        >> due
                        >> to exiting the method). The reason for this is that code compiled in
                        >> debug
                        >> mode will not have references released when they are no longer used.[/color]
                        >
                        > Are you sure it's a case of how it's compiled? I was under the
                        > impression that it was how it was being *run* - which would make sense,
                        > as if you're not running in the debugger, you don't need to know the
                        > value of c after the last use even if the debug symbols are present.
                        >
                        > When I get the chance I may test this in each configuration just to see
                        > what happens...
                        >
                        > --
                        > Jon Skeet - <skeet@pobox.co m>
                        > http://www.pobox.com/~skeet
                        > If replying to the group, please do not mail me too[/color]


                        Comment

                        • Jon Skeet [C# MVP]

                          #13
                          Re: &quot;using&quo t; vs &quot;= null&quot; and object lifetime

                          Ollie Riches <ollie.riches@p honeanalyser.ne t> wrote:[color=blue]
                          > Surely assigning an object to null at the end of a method will be optimized
                          > out during compilation?[/color]

                          Not during C#->IL compilation.
                          [color=blue]
                          > Or am I trying to second guess what goes on during compliation :)[/color]

                          Yup...

                          --
                          Jon Skeet - <skeet@pobox.co m>
                          Pobox has been discontinued as a separate service, and all existing customers moved to the Fastmail platform.

                          If replying to the group, please do not mail me too

                          Comment

                          • Jon Skeet [C# MVP]

                            #14
                            Re: &quot;using&quo t; vs &quot;= null&quot; and object lifetime

                            Jon Skeet [C# MVP] <skeet@pobox.co m> wrote:[color=blue][color=green]
                            > > This depends on how it is compiled. If you are compiling in debug mode,
                            > > then yes, it will make it GC faster (although how much faster is
                            > > questionable since c would have been released very quickly afterwards, due
                            > > to exiting the method). The reason for this is that code compiled in debug
                            > > mode will not have references released when they are no longer used.[/color]
                            >
                            > Are you sure it's a case of how it's compiled? I was under the
                            > impression that it was how it was being *run* - which would make sense,
                            > as if you're not running in the debugger, you don't need to know the
                            > value of c after the last use even if the debug symbols are present.
                            >
                            > When I get the chance I may test this in each configuration just to see
                            > what happens...[/color]

                            I've just tested this, and Nick's absolutely right. In fact, unlike
                            some other optimisations, this one looks like it's at the IL level,
                            rather than just being dependent on whether or not there's a pdb file
                            present. Here's the test program I used:

                            using System;

                            class Test
                            {
                            ~Test()
                            {
                            Console.WriteLi ne ("Finalized" );
                            }

                            static void Main()
                            {
                            Test t = new Test();

                            GC.Collect();
                            GC.WaitForPendi ngFinalizers();
                            Console.WriteLi ne ("After first collect");
                            t = null;
                            GC.Collect();
                            GC.WaitForPendi ngFinalizers();
                            Console.WriteLi ne ("After second collect");
                            }
                            }

                            When compiled in non-debug mode (or in debug "pdb only" mode) the
                            results are:

                            After first collect
                            Finalized
                            After second collect

                            When compiled in full debug mode, the results are:
                            Finalized
                            After first collect
                            After second collect

                            --
                            Jon Skeet - <skeet@pobox.co m>
                            Pobox has been discontinued as a separate service, and all existing customers moved to the Fastmail platform.

                            If replying to the group, please do not mail me too

                            Comment

                            • Jon Skeet [C# MVP]

                              #15
                              Re: &quot;using&quo t; vs &quot;= null&quot; and object lifetime

                              Jon Skeet [C# MVP] <skeet@pobox.co m> wrote:[color=blue]
                              > When compiled in non-debug mode (or in debug "pdb only" mode) the
                              > results are:
                              >
                              > After first collect
                              > Finalized
                              > After second collect
                              >
                              > When compiled in full debug mode, the results are:
                              > Finalized
                              > After first collect
                              > After second collect[/color]

                              Those should be the other way round, of course. Doh! Don't you just
                              hate it when you spot something wrong at the moment that the articles
                              just been posted?

                              --
                              Jon Skeet - <skeet@pobox.co m>
                              Pobox has been discontinued as a separate service, and all existing customers moved to the Fastmail platform.

                              If replying to the group, please do not mail me too

                              Comment

                              Working...