• Visitors can check out the Forum FAQ by clicking this link. You have to register before you can post: click the REGISTER link above to proceed. To start viewing messages, select the forum that you want to visit from the selection below. View our Forum Privacy Policy.
  • Want to receive the latest contracting news and advice straight to your inbox? Sign up to the ContractorUK newsletter here. Every sign up will also be entered into a draw to WIN £100 Amazon vouchers!

Garbage Collection rant

Collapse
X
  •  
  • Filter
  • Time
  • Show
Clear All
new posts

    Garbage Collection rant

    I did some C recently. I remembered stuff like no classes, having to use the keyword struct all the time, and declaring all your variables at the start of a function. The thing I'd forgotten was just how you did things in C. Anytime you allocate anything, you have to catch every possible exit to the function to make sure it's deleted no matter what.

    In C++, you have wrapper objects on the stack, and you can be certain that no matter what the destructors will be called on any kind of exit from the function (and the block) and clean up whatever it's wrapping. And not just for memory. The same technique works well for file handles, network sockets, thread safety, or just access to internal data structures, anything you like that you wouldn't want to get stuck in some kind of open state.

    So in the name of progress, I'm doing some C# (and C++/CLI, but that's a different story). You can't create objects on the stack any more, you have to create them on the heap with new. And even though at the end of the block there's no references to the object, you can't count on when it might be destroyed, which means you can't be sure when the access to the file / socket / internal data structure is closed. A bit of a major problem, if say for example, you opened a file with exclusive access. That file would stay locked and subsequent access to the file would fail.

    If you need to be sure of when whatever the object is managing is cleaned up, you can do it by calling Dispose, but then you're back to the C technique of having to make sure every possible exit from a function (including exceptions) calls Dispose. You've lost one of the major benefits of object oriented programming.

    There's another problem. A common C++ technique is to use reference counting, and a "last one to leave turn out the lights" approach. You could have 5 references to the same file, and when the last reference is released (i.e. it's wrapper goes out of scope), the file is closed. C# promises to give you the same, except having had to call Dispose() on one of the references, the other four now all point to what is essentially a dead object. There's no way to have the cleanup happen when the last reference is released other than waiting for the garbage collection to call finalize, but that's not something you can rely on.

    So you can't use Dispose and maintain multiple references to the same object, but you have to use Dispose if you ever want to be sure of proper cleanup. The only solution I can think of is to try to engineer the code in a way that you know where the last reference will be and only call Dispose for that reference, or of course implement reference counting (which would be ironic).

    Is this a step backwards, or is it just me?
    Will work inside IR35. Or for food.

    #2
    Dunno, I did some memory usage checks on my stuff before and after final tidying up and sticking disposes in everwhere and seemed exactly same. I am sure .net tidies up anyway, they just leave these things to make us geeks happy.
    bloggoth

    If everything isn't black and white, I say, 'Why the hell not?'
    John Wayne (My guru, not to be confused with my beloved prophet Jeremy Clarkson)

    Comment


      #3
      Originally posted by VectraMan View Post
      And even though at the end of the block there's no references to the object, you can't count on when it might be destroyed, which means you can't be sure when the access to the file / socket / internal data structure is closed. A bit of a major problem, if say for example, you opened a file with exclusive access. That file would stay locked and subsequent access to the file would fail.
      The Dispose method is pretty much designed to meet the requirement of explicit resource deallocation when you need to be sure that the resource has been cleaned up.

      Originally posted by VectraMan View Post
      If you need to be sure of when whatever the object is managing is cleaned up, you can do it by calling Dispose, but then you're back to the C technique of having to make sure every possible exit from a function (including exceptions) calls Dispose. You've lost one of the major benefits of object oriented programming.
      For methods where this is an issue then a common technique is to adopt a single exit point from the method. It's not as much of "commandment" for software development these days as it once was (rightly or wrongly) but can still be a useful technique. Use of try/finally can also alleviate this.

      Originally posted by VectraMan View Post
      There's another problem. A common C++ technique is to use reference counting, and a "last one to leave turn out the lights" approach. You could have 5 references to the same file, and when the last reference is released (i.e. it's wrapper goes out of scope), the file is closed. C# promises to give you the same, except having had to call Dispose() on one of the references, the other four now all point to what is essentially a dead object. There's no way to have the cleanup happen when the last reference is released other than waiting for the garbage collection to call finalize, but that's not something you can rely on.
      I don't quite follow the example - having 5 references to a file sounds like the design needs to be addressed? There may be an obvious example that I just haven't considered though

      Originally posted by VectraMan View Post
      So you can't use Dispose and maintain multiple references to the same object, but you have to use Dispose if you ever want to be sure of proper cleanup. The only solution I can think of is to try to engineer the code in a way that you know where the last reference will be and only call Dispose for that reference, or of course implement reference counting (which would be ironic).
      Sounds like a candidate for a semaphore?

      Originally posted by VectraMan View Post
      Is this a step backwards, or is it just me?
      I'd say a step forward - I personally find resource leaks are far less common these days. Or maybe I'm just a better coder now.
      Where are we going? And what’s with this hand basket?

      Comment


        #4
        Originally posted by voodooflux View Post
        For methods where this is an issue then a common technique is to adopt a single exit point from the method. It's not as much of "commandment" for software development these days as it once was (rightly or wrongly) but can still be a useful technique. Use of try/finally can also alleviate this.
        Well yes, but then the single exit point was what they told you to do with C, and C++ had a better approach. C# is a step backwards in that regard as you have to think about putting in try/finally all the time whereas proper use of stack based objects in C++ means you can largely ignore exceptions in all your intermediate levels.

        I don't quite follow the example - having 5 references to a file sounds like the design needs to be addressed? There may be an obvious example that I just haven't considered though
        Poor example perhaps. Imagine a data structure that has to be temporarily locked (i.e. put in read only mode) whilst some quick operation is performed on it. In C++ you can create a lock object on the stack knowing that it will definitely be unlocked at the end. If your code has to call other functions that also lock the data, then that's fine too (as long as everything is reference counted). The data structure stays locked until the first lock object is destroyed, which will definitely happen as the stack unwinds (even if an exception is thrown).

        In C++ you can design a simple interface like this that the caller must use and that's guaranteed to work without the caller having to carry out special operations specific to the implementation. This approach just doesn't work in C#. In C# the caller has to know what to do, and is resposible for your data structure being unlocked.

        Of course it could be designed differently, but that seems to me a step backwards towards a lesser OOP approach.

        I'd say a step forward - I personally find resource leaks are far less common these days. Or maybe I'm just a better coder now.
        Or maybe you just don't know about the resource leaks?

        I can see that it has advantages (performance saving of not freeing up all those objects for one), but I think it would have been much better if they'd allowed both approaches in C#.
        Will work inside IR35. Or for food.

        Comment


          #5
          My garbage was not collected last week : I must phone the council.

          IGMC......

          Comment


            #6
            Originally posted by VectraMan View Post
            Well yes, but then the single exit point was what they told you to do with C, and C++ had a better approach. C# is a step backwards in that regard as you have to think about putting in try/finally all the time whereas proper use of stack based objects in C++ means you can largely ignore exceptions in all your intermediate levels.
            I personally think that try/finally is an elegant an uncluttered approach to this - it's not something I have to think about any more, it just comes naturally. And you don't have to handle the exception, just let it propagate.

            Originally posted by VectraMan View Post
            Poor example perhaps. Imagine a data structure that has to be temporarily locked (i.e. put in read only mode) whilst some quick operation is performed on it. In C++ you can create a lock object on the stack knowing that it will definitely be unlocked at the end. If your code has to call other functions that also lock the data, then that's fine too (as long as everything is reference counted). The data structure stays locked until the first lock object is destroyed, which will definitely happen as the stack unwinds (even if an exception is thrown).

            In C++ you can design a simple interface like this that the caller must use and that's guaranteed to work without the caller having to carry out special operations specific to the implementation. This approach just doesn't work in C#. In C# the caller has to know what to do, and is resposible for your data structure being unlocked.

            Of course it could be designed differently, but that seems to me a step backwards towards a lesser OOP approach.
            Apologies if I haven't understood the example correctly, but this sounds like something that can be easily achieved (and insulated from the caller) by using "lock" and Mutex objects within the implementation of the data structure.

            Originally posted by VectraMan View Post
            Or maybe you just don't know about the resource leaks?
            Always a possibility! Although my current projects are services required to run 24/7 so a lot of runtime performance analysis is done prior to deployment. Such issues are certainly fewer and far between in the managed environment from my experience.
            Where are we going? And what’s with this hand basket?

            Comment


              #7
              Originally posted by BrilloPad View Post
              My garbage was not collected last week : I must phone the council.

              IGMC......
              < hands BP his coat, and phones for a taxi >
              Where are we going? And what’s with this hand basket?

              Comment


                #8
                If you design your code correctly, you will only have 1 exit from a function.

                Comment


                  #9
                  Originally posted by Churchill View Post
                  If you design your code correctly, you will only have 1 exit from a function.

                  indeed. I usually have an END statement just before the return and use GOTO END throughout the function.

                  HTH

                  Comment


                    #10
                    Just define your variables in WORKING-STORAGE
                    Your parents ruin the first half of your life and your kids ruin the second half

                    Comment

                    Working...
                    X