Go Back  Xtreme Visual Basic Talk > General Discussion > Tech Discussions > A stupid question about .Net garbage collection and bad code (bad scoping)


Reply
 
Thread Tools Display Modes
  #1  
Old 07-15-2012, 01:53 PM
surfR2911 surfR2911 is offline
Contributor
 
Join Date: Oct 2009
Posts: 719
Default A stupid question about .Net garbage collection and bad code (bad scoping)


This is probably going to get a responses that say "use good scoping" but
I'll ask it anyway because VB6 didn't really have a special garbage collector and
I'm curious about getting feedback in regard to how "good" (real super
smart and efficient) garbage collection should work.
(..and I know that no GC can never be 100% efficient but..)

Let's say I'm a noob VB.Net programmer
(and some days I feel more of a newbie VB.Net programmer than others,
but that's besides the point..).

I need to load a bitmap and do some manipulation on it.
My fantastic code looks like:
Code:
Public Class Form1
  Private m_Bitmap As Bitmap

  Private Sub Form1_Load(sender As Object, e As System.EventArgs) Handles Me.Load
    Dim strFilename As String = "C:\superhuge_2560px_by_2048px_32bpp.bmp"
    m_Bitmap = New Bitmap(strFilename)
    BadBitmapScoping()
  End Sub

  Private Sub BadBitmapScoping()
    Dim bm As Bitmap = Nothing
    bm = m_Bitmap
    'perform some bitmap manipulation here..
    '
    '
  End Sub
End Class
Of course the experts on the forum are just shaking their collective heads
going "tsk, tsk, tsk" at the many errors.

Some will point out that it's m,ore "polite" to not lock up the bitmap file this way,
but instead use code to "Load a picture so it doesn't lock the picture file in VB .NET".

Others will point out (ask):
"Shouldn't that be a function instead of a sub so it returns
the manipulated bitmap for use in other parts of the program?".

But the most glaring error is the bad scoping - setting up a module level variable that
gets assigned to a locally scoped variable is a bad practice in this case,
when simply using a local variable would gave been better
(and would have helped the garbage collector,
because the bitmap, after being loaded, isn't need/used anymore after
the manipulated bitmap is created).

How can/should the .Net GC handle this situation?
(and/or what is the degree that the GC can/should compensate for this bad coding?)

Because of the module level assignment,
it basically means our superhuge bitmap
(which should be a png if its going to use 32bpp alpha, but anyways..),
is going to be hanging out in memory until the program ends
and/or possibly if the form goes out of scope.

A secondary question - should the IDE be raising some kind of warning about this?

I tried this code out in VB.Net 2010 Express Edition and no error or warning is raised (so the IDE auto-correct had no suggestions..)

If the .Net IDE was smart enough to detect this bad scoping,
what should it do about it?

I have a bad feeling it would never be smart enough to
directly correct the bad scoping code.

Instead I think if it did detect it,
it's auto-correct suggestion it might be to
add a bm.Dispose() statement:
Quote:
Private Sub BadBitmapScoping()
Dim bm As Bitmap = Nothing
bm = m_Bitmap
'perform some bitmap manipulation here..
'
bm.Dispose()
End Sub
..which would of course do nothing about the module level scoped bitmap.

The other option might be for the compiler to somehow do something to compensate for the bad scoping,
but I don't know enough about compiler technology to know about what could be done at that level.

Last edited by surfR2911; 07-15-2012 at 02:03 PM.
Reply With Quote
  #2  
Old 07-15-2012, 03:05 PM
dilettante's Avatar
dilettante dilettante is offline
Underclocked lifestyle

Forum Leader
* Guru *
 
Join Date: Feb 2005
Location: Michigan, USA
Posts: 4,184
Default

Perhaps you could tell us what got you to this point, i.e. what the real issue is.

There are things you can do that defeat/hamper GC and things you can do that assist GC... but GC is always part of life in .Net and Java. So much so that some classes of application just aren't ever going to perform well.


BTW: VB6 does not use GC at all for the most part. For example COM object disposal is entirely deterministic and happens immediately so it can never "get behind" and cause those intermittent process freeze-ups. The one place VB6 does use a GC mechanism is for its short-Strings pool page, but this has always been a serious enough issue that most people code around the problems it can cause (it is part of the reason for performance problems due to "too much" concatenation).
Reply With Quote
  #3  
Old 07-15-2012, 03:16 PM
surfR2911 surfR2911 is offline
Contributor
 
Join Date: Oct 2009
Posts: 719
Default Assisting the GC and/or not doing stupid things to hamper it..

Quote:
Originally Posted by dilettante
There are things you can do that defeat/hamper GC and things you can do that assist GC..
Thanks for the reply.
Of course I want to assist the GC,
but I'm worried (as a VB.Net newbie)
that my writing of lackluster code is, as you say,
"defeating/hampering" the GC.

Is there a good article (link or two that you would recommend) that shows all/most
of the good practices designed to assist the GC?

I read through this article and got something out of it.
It seems to warn of the unwise use of the System.GC.Collect() method,
Quote:
System.GC.Collect() method
The System.GC class provides a Shared method named Collect() which enforces the Garbage Collection to commence at your command.
It is usually better to leave the invocation of the Garbage Collector to the .Net Runtime.
It is not wise to start a Garbage Collector process just for freeing some objects in memory.
Although you may use the method when a large number of objects in your program are un-referenced
(E.g., an array or a collection) and you want the memory to be re-claimed instantly.
..but didn't really got into specific guidelines for the wise use of it.

I have found some GC info, but it tends to be widely scattered and
somewhat "general-istic/generic" (as in good .Net coding in general helps
the GC, I know, but I'd be looking for something more specific than that).

Quote:
Originally Posted by dilettante
The one place VB6 does use a GC mechanism is for its short-Strings pool page,
but this has always been a serious enough issue that most people code around the problems it can cause
(it is part of the reason for performance problems due to "too much" concatenation).
Yes I knew about that.
That's why I didn't want to say that VB6 had no GC at all.

Last edited by surfR2911; 07-15-2012 at 03:29 PM.
Reply With Quote
  #4  
Old 07-15-2012, 06:30 PM
PlausiblyDamp's Avatar
PlausiblyDamp PlausiblyDamp is offline
Ultimate Contributor

Forum Leader
* Expert *
 
Join Date: Nov 2003
Location: Wigan, UK
Posts: 1,676
Default

By and large the GC does a pretty decent job of handling memory for you as a developer, however like all systems it does need a helping hand on occasion.

If you are planning on using a class level variable to hold potentially large amounts of information then you will need to consider the options.

Firstly if the variable's contents have a life time tied to the lifetime of the class then doing nothing and letting the garbage collector handle it is the easiest option. However you do need to be careful if this variable will hold onto (either directly or indirectly) an expensive resource such as a file handle or database connection; in these cases the best option is to do as you have suggested and open the file / connection etc, get the data and store the data and then close the file / connection.

If the object isn't tied directly to the lifetime of the class i.e. you may open a file, grab the contents but then later no longer need the contents then things are a little trickier as there is no automatic way for the compiler to realise this. You would either need to make sure you are setting this member to nothing (or disposing of it) when you no longer need it to allow the GC a better chance of freeing up the memory.

If the variable is acting more like a cache and the contents could easily be recreated but at a performance cost then a weak reference might be a useful way of dealing with the issue.

GC.Collect is almost always a bad idea as although it can cause some memory to be freed up at the point it is called it can actually cause other objects to take longer to be freed up and this often will offset any benefits gained by forcing it in the first place.

This situation unfortunately is likely to need to be dealt with on a case by case basis and nothing other than general guidelines are likely to be applicable.
__________________
Intellectuals solve problems; geniuses prevent them.
-- Albert Einstein

Posting Guidelines Forum Rules Use the code tags
Reply With Quote
  #5  
Old 07-15-2012, 07:14 PM
passel's Avatar
passel passel is offline
Sinecure Expert

Super Moderator
* Guru *
 
Join Date: Jun 2003
Location: Upstate New York, usa
Posts: 7,714
Default

Quote:
'...
bm = m_Bitm
ap
'perform some bitmap manipulation here..
'
bm.Dispose()
End Sub

..which would of course do nothing about the module level scoped bitmap.
Not true.
Bitmaps are reference types.
Since you set bm to m_Bitmap, disposing of bm disposes the bitmap that both variables are referencing.
Likewise any modification of bitmap referenced by bm affects m_Bitmap since they are referencing the same bitmap.
__________________
There Is An Island Of Opportunity In The Middle of Every Difficulty.
Miss That, Though, And You're Pretty Much Doomed.
Reply With Quote
  #6  
Old 07-16-2012, 02:32 PM
surfR2911 surfR2911 is offline
Contributor
 
Join Date: Oct 2009
Posts: 719
Default more GC info..plus a bit on appdomains, multi-threading and heap compaction

Quote:
Originally Posted by PlausiblyDamp
If the object isn't tied directly to the lifetime of the class
i.e. you may open a file, grab the contents but then later no longer need the contents then things are a little trickier
as there is no automatic way for the compiler to realize this.
You would either need to make sure you are setting this member to nothing
(or disposing of it) when you no longer need it to allow the GC a better chance
of freeing up the memory
I wondered about this --whether there was a way to not have to manually dispose
and make the GC "wake-up" and take some clean-up action automatically.

Quote:
Originally Posted by PlausiblyDamp
If the variable is acting more like a cache and the contents
could easily be recreated but at a performance cost then a weak reference might be
a useful way of dealing with the issue.
Thanks for the link, but there another link (off that page that you linked to),
that offered "Guidelines for Using Weak References"
which was actually aligned with the my goal of finding some guidelines.

Quote:
Originally Posted by PlausiblyDamp
This situation unfortunately is likely to need to be dealt with
on a case by case basis and nothing other than general guidelines are likely to be applicable.
That's disappointing, but I'm still hopeful to find some "best practices",
and/or "tips and tricks", to write more "CG-friendly" code.

Quote:
Originally Posted by passel
Since you set bm to m_Bitmap, disposing of bm disposes the bitmap that both variables are referencing.
Likewise any modification of bitmap referenced by bm affects m_Bitmap since they are referencing the same bitmap.
Thank you for the clarification.
I couldn't find anyplace that clear (definitively) said this was the case.

Some other things..
I have started getting into marshaling..an specifically using the MarshalByRefObject Class,
which is generally used in conjunction with AppDomains.

This in turn leads into parallelization and using the gcServer as mentioned
in this StackOverFlow thread:
"How can I improve garbage collector performance of .NET 4.0 in highly concurrent code?".

However I am really afraid to start using AppDomains and gcServer when I see articles like these:
Why does calling AppDomain.Unload doesn't result in a garbage collection?
gcServer enabled = true leads to SIGNIFICANT memory usage.

So should I not use AppDomains at all, or just not use gcServer,
or is there a designated way to use AppDomains in a way that is "GC-friendly".

I read in this xvbt thread that static types in AppDomains stick around forever,
so reference counting is "pretty much the only way you can get a good indication
of when to get rid of them" but then it says
you can't get rid of them until the AppDomain shuts down (unloads).

I found a few old articles on reference counting:
Reference Counting, Garbage Collection, and Object Lifetime
http://msdn.microsoft.com/en-us/libr...=vs.71%29.aspx
Back To Basics: Reference Counting Garbage Collection.

However, shouldn't you also be monitoring memory usage?
I found the GC.GetTotalMemory method but that's not the same as
monitoring memory for a process because according to this article:
Quote:
Under the .NET platform, executables are not hosted directly within a Windows process,
as is the case in traditional unmanaged applications.
Rather, a .NET executable is hosted by a logical partition
within a process termed an application domain.
As you will see, a single process may contain multiple application domains,
each of which is hosting a .NET executable.
This additional subdivision of a traditional Windows process offers several benefits..
I've also been reading up a little on threading and specifically:
MSDN: SynchronizationContext Class
Understanding SynchronizationContext (Part I)
Quote:
Note: I could get past Part1 because Part II goes into:
A long time ago..developers coded COM classes that could only run on Single Apartment Threads (STA).
Why? Because the COM runtime would handle thread marshaling for the developer,
and always made sure that your COM class would execute on the same thread.
This way, the COM developer did not need to worry about multi-threading,
Mutexes, Semaphores, Events, and all the other multi-threading toys out there.
Just for the record, COM also provided a Multi-Threading Apartment model (for the brave ones).
With MTA, the developer had to worry about multi-threading issues, but had more control.
..stuff that I never dealt with under VB6.

This lead me to a whole bunch of articles on GC and how it combats something
called "heap fragmentation" with "heap compaction"
and this stackoverflow thread says:
Quote:
After marking objects as unused (candidates to be deleted) GC executes Plan phase.
"Plan: The .NET garbage collector creates a generation budget
for each generation being collected and then determines the amount of fragmentation
that will occur in the managed heap
as a result of the GC to decide whether compaction will be productive."
That was a bit vague, but later in the thread it became a little more clear:
Quote:
The GC is lazy to be efficient.
It will not actually free or as you say 'compact' until it needs to.
The object has been moved to a dispose queue.
You can wait days and not see it clean up.
It will clean up when resources are low and it needs to.
I lot of people don't like stackoverflow but I agree with AtmaWeapon's comments
in this xvbt thread that talks about SO versus xvbt.

Anyway, lastly, I want to mention Multi-threading in VB.Net.
Most of the .Net multi-threading articles I find that do mention garbage collection
are pretty heavy with C#.Net code --like this one,
so I'm still looking around for such articles with VB.Net code.

I've played around around with the BackgroundWorker class but according to that MSDN page:
Quote:
BackgroundWorker events are not marshaled across AppDomain boundaries.
Do not use a BackgroundWorker component to perform
multithreaded operations in more than one AppDomain.
So who knows how you would write multi-threaded VB.Net code
in such a way as to make it "GC-friendly"?

Last edited by surfR2911; 07-16-2012 at 05:03 PM.
Reply With Quote
Reply


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off

Forum Jump

Advertisement:





Free Publications
The ASP.NET 2.0 Anthology
101 Essential Tips, Tricks & Hacks - Free 156 Page Preview. Learn the most practical features and best approaches for ASP.NET.
subscribe
Programmers Heaven C# School Book -Free 338 Page eBook
The Programmers Heaven C# School book covers the .NET framework and the C# language.
subscribe
Build Your Own ASP.NET 3.5 Web Site Using C# & VB, 3rd Edition - Free 219 Page Preview!
This comprehensive step-by-step guide will help get your database-driven ASP.NET web site up and running in no time..
subscribe
 
 
-->