Results 1 to 12 of 12

Thread: VB: Using statement still uses too much memory - Solved

  1. #1

    Thread Starter
    Addicted Member NinjaNic's Avatar
    Join Date
    Dec 2013
    Location
    Earth
    Posts
    230

    VB: Using statement still uses too much memory - Solved

    Hi!
    I guess I must still be a newbie at this.

    So, I'm making a game which heavily uses graphics. I heard that the Using statement is supposed to dispose all resources from that element when it reaches End Using. However in Debug mode, the memory still rises to a scary amount (1 GB) before automatically disposing resources.
    Would it be more efficient, or more risky, or just plain stupid to call GC.Collect() every frame of the game? Does GC remove all unnecessary resources from all parts of the program, or just in that Sub, or .VB file?

    Anyway, here's an example of my code:

    Code:
        Private Sub Form1_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
    
            Dim Screen_W As Int32 = 6
            Dim Screen_H As Int32 = 6
    
            Dim srcR As New Rectangle(0, 0, Screen_W * 24, Screen_H * 24)
    
            Dim B As New Bitmap(Screen_W * 24, Screen_H * 24)
    
            Using G As Graphics = Graphics.FromImage(B)
                Select Case Lv
                    Case Level.Lv1
                        ' G.DrawImage ... (a lot)
                    Case Level.Lv2
                        ' G.DrawImage ... (a lot)
                End Select
            End Using
    
            e.Graphics.DrawImage(B, ClientRectangle, srcR, GraphicsUnit.Pixel)
    
        End Sub
    (Form1_Paint happens very frequently.)

    Thanks in advance for the help!
    ~Nic
    Last edited by NinjaNic; Sep 13th, 2016 at 10:52 PM.

  2. #2
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,344

    Re: VB: Using statement still uses too much memory

    Disposing an object has nothing directly to do with how much memory you use. The memory occupied by an object is NOT recovered when it is disposed. An object must be disposed in order for its memory to be recovered, so disposing an object means that its memory can likely be recovered sooner, but the memory will still not be recovered until the GC runs.

    If you're calling DrawImage a lot then presumably you have other Images that you're drawing onto B. It's going to be those Images that are chewing up all your memory. You need to make sure that you're disposing them when you're done with them and then they can be cleaned up when the GC runs. Even then, you may still need to call GC.Collect explicitly at intervals if you're chewing up lots of memory in tight code because the GC may not run itself until that code completes.

  3. #3
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,344

    Re: VB: Using statement still uses too much memory

    Also, do you really need to draw all those other Images onto a new Bitmap on every Paint? Maybe you do or maybe it could be done more efficiently, e.g. start with the same Bitmap as last time and just draw onto it what has changed, meaning you'd be requesting less memory in the first place.

  4. #4
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,344

    Re: VB: Using statement still uses too much memory

    Also, you should be disposing B once you're done with it too. You should be disposing EVERY disposable object that you create once you're done with it. You should have a second Using statement for that. Always use a Using statement to create and destroy disposable objects if you can.

  5. #5
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    39,038

    Re: VB: Using statement still uses too much memory

    There are limitations for that kind of graphics in .NET. The GC will collect the memory, but calling GC.Collect is generally going to be only slightly better than letting it run itself. It will either be horrible either way or it will be fine either way. If it is fine either way, then don't bother calling it. If it is horrible either way, then it barely matters which you do, right?

    Garbage collection is potentially a noticeably slow process. So, you get to decide whether you can afford the cost. I was doing something that required composing on a series of up to a few hundred bitmaps, depending on zoom level. I found that the cost of doing the drawing was simply too high. My first solution was pre-computing all the images on startup and caching them. If any one image changed, I'd invalidate that cache such that it had to be redrawn (though all the others could stay the same). I took that as far as I could, but eventually found that there was a reasonably common scenario that required me to redraw ALL the cached images, which was now terribly slow (10-20 seconds). At that point, I switched to using XNA for the drawing and everything was blazingly fast. It's all a trade you get to make.
    My usual boring signature: Nothing

  6. #6
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,582

    Re: VB: Using statement still uses too much memory

    I'm pretty sure not disposing of bitmap B is the main culprit here, as jmcilhinney pointed out.

    I do a lot of drawing to plots continually (generally map type plots updated at 10 hz, based on data coming in at 50hz each from a number of different applications running simultaneously on the same computer). There are other programs on other computers also interfacing with the same program (which is why the program exists), so the suite of applications running are often started and can run for weeks at a time since the users don't often have a need to restart them.
    None of these programs chew up memory because of drawing. We were shutdown this weekend, so at this point I'm looking at one program that has only been running for 2 and 1/2 days, refreshing the plot continuously over this period of time as simulated vehicles move around. The memory is rock steady at 18,356K, not growing at all for the whole period I've been watching it. It has six background thread, five of which are supporting the different network interfaces.

    Making sure that every object I create that has a Dispose method, calls that Dispose method (or uses Using) has worked fine for me for many applications for several years.
    I'm looking at another of my application that runs continuously, capturing a portion of the desktop and transmitting that over a TCP connecton to someone on the other side of the lab. That also runs 24x7 generally, and allows the user to monitor the applications on my machine from his machine. He can also click and drag on the image of that portion of the desktop on his machine, and have those replicated in the screen area of the source machine, like Windows Remote Desktop, or other desktop sharing mechanism, but without having to share the whole desktop, or switch users.
    That application does show memory changes, but not endless growing. It toggles back and forth between about 28MB and 30MB fairly regularly, so must jump up as it captures the screen and streams it out, but then releases that memory relatively quickly when done with it.

    So, just dispose of all your disposables as soon as you're done with them, and you will no doubt have much improved results.

    p.s. It looks like the bitmap is only 144x144 pixels, so isn't all that large, so it is surprising that you would have a lot of drawing to do in such a small area.
    But as jmc' also pointed out, if you're going to be drawing the same thing over and over (the level doesn't change often), then keeping the bitmap around at a outer scope, and only redrawing it when it needs to be done, saves all that churning when you get the paint event. You only need to draw the last updated version of the bitmap to the form.
    I guess I'm not saying anything really new, but just emphasizing what has been said already.
    Last edited by passel; Sep 8th, 2016 at 06:50 PM.

  7. #7

    Thread Starter
    Addicted Member NinjaNic's Avatar
    Join Date
    Dec 2013
    Location
    Earth
    Posts
    230

    Re: VB: Using statement still uses too much memory

    All right, thanks guys! Using the Using statement (Using the Using? What?) for the bitmap seems to work. The reason I need it to redraw every tick is because it is a scrolling background, so it's constantly changing. (So, one if the images it draws onto the bitmap is the background - much bigger than 144x144px.)

    Thanks for the help, all!

    Which types (other than bitmap and graphics) can be disposed? I looked up "disposable objects vb" and "list of disposable objects vb" but I couldn't find anything. And just to verify, any object that has a .dispose() method can be put in a Using statement, correct?

  8. #8
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,344

    Re: VB: Using statement still uses too much memory

    You're not really going to find a list of disposable types because there would be too many of them and it wouldn't cover third-party types anyway. Basically, any type that implements the IDisposable interface can be disposed. You don't have to implement that interface but it would be bad practice not to. If in doubt, check the documentation to see whether the type of interest does indeed implement IDisposable. It's a simple case of clicking on the type or a variable of that type and hitting F1. Alternatively, you can create a Using statement and the compiler will tell you if the object can't be disposed.

    As suggested, you should always dispose a disposable object if you created it and sometimes if you didn't create it too. If the creation and destruction are to happen within the same scope then a Using block should always be preferred. Remember that an object created with a Using statement is 100% guaranteed to be disposed, even if an exception is thrown within the Using block.

  9. #9

    Thread Starter
    Addicted Member NinjaNic's Avatar
    Join Date
    Dec 2013
    Location
    Earth
    Posts
    230

    Re: VB: Using statement still uses too much memory

    Ok, thanks for the advice! But what happens if I return an object? Will it still be disposed?

    (I typed this manually so there could be some errors.)
    Code:
    Function Test() as Bitmap
      Using B as Bitmap
        Return B
      End Using
    End Function

  10. #10
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,344

    Re: VB: Using statement still uses too much memory

    Quote Originally Posted by NinjaNic View Post
    Ok, thanks for the advice! But what happens if I return an object? Will it still be disposed?

    (I typed this manually so there could be some errors.)
    Code:
    Function Test() as Bitmap
      Using B as Bitmap
        Return B
      End Using
    End Function
    It's very simple. If you create an object with a Using statement, that object is guaranteed to be disposed when execution exits the Using block, regardless of what happens inside that block. If you return from a method then obviously execution has exited that Using block so obviously the object you created is disposed. The point of Using is to create a scope, i.e. you create, use and destroy and object in the scope of that Using block. If you intend to use the object outside that scope then don't use a Using statement. In that case, you may just have to call Dispose explicitly when you're done with the object. I say "may" because the caller of that method could always use a Using block, i.e.
    Code:
    Using myBitmap = Test()
        'Use myBitmap here.
    End Using
    You should only do that sort of thing, i.e. use a Using statement when the object comes from a method rather than a constructor, when you know that the object returned by the method will not be used elsewhere. If the method does or might put a reference elsewhere that some other code needs to use then it's not safe to dispose the object when you're done with it in that scope. It's usually quite simple to determine when and where to dispose an object but there are some cases where it can be quite curly.

  11. #11

    Thread Starter
    Addicted Member NinjaNic's Avatar
    Join Date
    Dec 2013
    Location
    Earth
    Posts
    230

    Re: VB: Using statement still uses too much memory

    Thank you for the help!

  12. #12
    PowerPoster Jenner's Avatar
    Join Date
    Jan 2008
    Location
    Mentor, OH
    Posts
    3,712

    Re: VB: Using statement still uses too much memory

    Quote Originally Posted by Shaggy Hiker View Post
    At that point, I switched to using XNA for the drawing and everything was blazingly fast.
    I remember that, you're welcome.

    @NinjaNic, if you're somewhat serious about games and graphics in VB.NET, I'd look at XNA. As Shaggy mentioned, it's blazingly fast for drawing graphics to the screen. I still have plenty of examples and many are posted on here. Of course, since XNA is no longer being actively maintained by Microsoft, you may want to explore MonoGame, the open-source free, actively developed, cross-platform successor to XNA.
    My CodeBank Submissions: TETRIS using VB.NET2010 and XNA4.0, Strong Encryption Class, Hardware ID Information Class, Generic .NET Data Provider Class, Lambda Function Example, Lat/Long to UTM Conversion Class, Audio Class using BASS.DLL

    Remember to RATE the people who helped you and mark your forum RESOLVED when you're done!

    "Two things are infinite: the universe and human stupidity; and I'm not sure about the universe. "
    - Albert Einstein

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width