473,799 Members | 3,740 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Strange GC behaviour - or - my inexperience :-)

Hi,

I have figured out that .NET CLR implements object destruction on the
knowledge of usage of
these objects. My DBHelper class closes the connection when refcount
goes to zero. That happens inside Finalize.

The sample code at the end crashes when I not do a call to getReader
with an empty string.
That is used as a Dummy for ' This object is used until here '
information.

If I use the last getReader line, All is fine.

I came from C++ and expected that GC doesn't touch objects in the same
scope (stack).

This makes me struggling on how to close connections automatically in
Finalize whithout
explicitly set the object to NULL. (In C++ I have smart pointers that
do this for me)

Any Ideas ?

Thanks, Lothar

Public Class DBHelper
Shared conn As SqlClient.SqlCo nnection
Shared refcount As Integer

Public Sub New(ByVal where As String)
refcount = refcount + 1
End Sub

Public Function getReader(ByVal SQL As String) As
SqlClient.SqlDa taReader
Dim mycmd As SqlClient.SqlCo mmand
Dim reader As SqlClient.SqlDa taReader = Nothing

' Return on empty query

If SQL = "" Then
Return Nothing
End If

Try
If conn Is Nothing Then
conn = New
SqlClient.SqlCo nnection("conne ctionstring")
End If
conn.Open()
Catch ex As Exception

' Log some information
conn = Nothing
Return Nothing
End Try

mycmd = conn.CreateComm and
mycmd.CommandTe xt = SQL

Try
reader = mycmd.ExecuteRe ader()
'CommandBehavio r.CloseConnecti on)
Catch ex As Exception

' Log some information
reader = Nothing
Return Nothing
End Try
Return reader
End Function

Protected Overrides Sub Finalize()
If refcount 0 Then
refcount = refcount - 1

If refcount = 0 Then
Try
conn.Close()
conn = Nothing
Catch ex As Exception

End Try
End If
End If
MyBase.Finalize ()
End Sub
Sample:

Public Sub SomeFunction()
Dim dbHelper As DBHelper = New DBHelper()
Dim reader As SqlClient.SqlDa taReader

Dim SQL As String = "SELECT * from SomeTable"
reader = dbHelper.getRea der(SQL)

GC.Collect() ' A
Collect to be appear explicitly or indirectly in

' my code
System.Threadin g.Thread.Sleep( 10) ' Some time
consumption

If Not reader Is Nothing Then
While
reader.Read() ' Crash
Dim SomeField As String = reader.GetValue (0)
End While
End If

'dbHelper.Execu teScalar("") ' Doesn't crash when
this line is uncommented.
End Sub

Apr 19 '07 #1
7 1560

Implement the IDisposable pattern, disposing the connection in "Dispose",
not Finalize.

Public MyClass
Implements IDisposable

...

End Class

<lo************ @lollisoft.dewr ote in message
news:11******** *************@q 75g2000hsh.goog legroups.com...
Hi,

I have figured out that .NET CLR implements object destruction on the
knowledge of usage of
these objects. My DBHelper class closes the connection when refcount
goes to zero. That happens inside Finalize.

The sample code at the end crashes when I not do a call to getReader
with an empty string.
That is used as a Dummy for ' This object is used until here '
information.

If I use the last getReader line, All is fine.

I came from C++ and expected that GC doesn't touch objects in the same
scope (stack).

This makes me struggling on how to close connections automatically in
Finalize whithout
explicitly set the object to NULL. (In C++ I have smart pointers that
do this for me)

Any Ideas ?

Thanks, Lothar

Public Class DBHelper
Shared conn As SqlClient.SqlCo nnection
Shared refcount As Integer

Public Sub New(ByVal where As String)
refcount = refcount + 1
End Sub

Public Function getReader(ByVal SQL As String) As
SqlClient.SqlDa taReader
Dim mycmd As SqlClient.SqlCo mmand
Dim reader As SqlClient.SqlDa taReader = Nothing

' Return on empty query

If SQL = "" Then
Return Nothing
End If

Try
If conn Is Nothing Then
conn = New
SqlClient.SqlCo nnection("conne ctionstring")
End If
conn.Open()
Catch ex As Exception

' Log some information
conn = Nothing
Return Nothing
End Try

mycmd = conn.CreateComm and
mycmd.CommandTe xt = SQL

Try
reader = mycmd.ExecuteRe ader()
'CommandBehavio r.CloseConnecti on)
Catch ex As Exception

' Log some information
reader = Nothing
Return Nothing
End Try
Return reader
End Function

Protected Overrides Sub Finalize()
If refcount 0 Then
refcount = refcount - 1

If refcount = 0 Then
Try
conn.Close()
conn = Nothing
Catch ex As Exception

End Try
End If
End If
MyBase.Finalize ()
End Sub
Sample:

Public Sub SomeFunction()
Dim dbHelper As DBHelper = New DBHelper()
Dim reader As SqlClient.SqlDa taReader

Dim SQL As String = "SELECT * from SomeTable"
reader = dbHelper.getRea der(SQL)

GC.Collect() ' A
Collect to be appear explicitly or indirectly in

' my code
System.Threadin g.Thread.Sleep( 10) ' Some time
consumption

If Not reader Is Nothing Then
While
reader.Read() ' Crash
Dim SomeField As String = reader.GetValue (0)
End While
End If

'dbHelper.Execu teScalar("") ' Doesn't crash when
this line is uncommented.
End Sub

Apr 19 '07 #2
On 19 Apr., 11:52, "Duracel" <Dura...@nospam .comwrote:
Implement the IDisposable pattern, disposing the connection in "Dispose",
not Finalize.

Public MyClass
Implements IDisposable

...

End Class

<lothar.behr... @lollisoft.dewr ote in message

news:11******** *************@q 75g2000hsh.goog legroups.com...
Hi,
I have figured out that .NET CLR implements object destruction on the
knowledge of usage of
these objects. My DBHelper class closes the connection when refcount
goes to zero. That happens inside Finalize.
The sample code at the end crashes when I not do a call to getReader
with an empty string.
That is used as a Dummy for ' This object is used until here '
information.
If I use the last getReader line, All is fine.
I came from C++ and expected that GC doesn't touch objects in the same
scope (stack).
This makes me struggling on how to close connections automatically in
Finalize whithout
explicitly set the object to NULL. (In C++ I have smart pointers that
do this for me)
Any Ideas ?
Thanks, Lothar
Public Class DBHelper
Shared conn As SqlClient.SqlCo nnection
Shared refcount As Integer
Public Sub New(ByVal where As String)
refcount = refcount + 1
End Sub
Public Function getReader(ByVal SQL As String) As
SqlClient.SqlDa taReader
Dim mycmd As SqlClient.SqlCo mmand
Dim reader As SqlClient.SqlDa taReader = Nothing
' Return on empty query
If SQL = "" Then
Return Nothing
End If
Try
If conn Is Nothing Then
conn = New
SqlClient.SqlCo nnection("conne ctionstring")
End If
conn.Open()
Catch ex As Exception
' Log some information
conn = Nothing
Return Nothing
End Try
mycmd = conn.CreateComm and
mycmd.CommandTe xt = SQL
Try
reader = mycmd.ExecuteRe ader()
'CommandBehavio r.CloseConnecti on)
Catch ex As Exception
' Log some information
reader = Nothing
Return Nothing
End Try
Return reader
End Function
Protected Overrides Sub Finalize()
If refcount 0 Then
refcount = refcount - 1
If refcount = 0 Then
Try
conn.Close()
conn = Nothing
Catch ex As Exception
End Try
End If
End If
MyBase.Finalize ()
End Sub
Sample:
Public Sub SomeFunction()
Dim dbHelper As DBHelper = New DBHelper()
Dim reader As SqlClient.SqlDa taReader
Dim SQL As String = "SELECT * from SomeTable"
reader = dbHelper.getRea der(SQL)
GC.Collect() ' A
Collect to be appear explicitly or indirectly in
' my code
System.Threadin g.Thread.Sleep( 10) ' Some time
consumption
If Not reader Is Nothing Then
While
reader.Read() ' Crash
Dim SomeField As String = reader.GetValue (0)
End While
End If
'dbHelper.Execu teScalar("") ' Doesn't crash when
this line is uncommented.
End Sub- Zitierten Text ausblenden -

- Zitierten Text anzeigen -
As of the documentation it does the same as Finalize. I cannot
guarantee, that the reader is usable after getReader(...).

It is the time, when GC calls Finalize or now Dispose through
Finalize. It appears BEFORE my function block is leaving.

I have to go through my whole project and add this dummy call to avoid
too early object destructions.

That's bad.

Apr 19 '07 #3

imho, where you are using resources that implement IDisposable, you should
dispose of them yourself, rather than waiting for the GC to kick in. From a
C++ background, you are used to deterministic object destruction - whereas
you never really know with .NET when the object will be disposed so in cases
where its important to manage resources, you should make sure it happens
when you want it to:

Using g as Graphics = myControl.Creat eGraphics ()

End Using

' g has automagically been disposed, even if an exception occurs
or
Dim g as Graphics = Nothing

Try

g = myControl.Creat eGraphics ()

Finally

' g gets disposed, even if an exception occurs

If g IsNot Nothing Then
g.Dispose ()
End If

End Try
Apr 19 '07 #4
On 19 Apr., 12:21, "Duracel" <Dura...@nospam .comwrote:
imho, where you are using resources that implement IDisposable, you should
dispose of them yourself, rather than waiting for the GC to kick in. From a
C++ background, you are used to deterministic object destruction - whereas
you never really know with .NET when the object will be disposed so in cases
where its important to manage resources, you should make sure it happens
when you want it to:

Using g as Graphics = myControl.Creat eGraphics ()

End Using

' g has automagically been disposed, even if an exception occurs

or

Dim g as Graphics = Nothing

Try

g = myControl.Creat eGraphics ()

Finally

' g gets disposed, even if an exception occurs

If g IsNot Nothing Then
g.Dispose ()
End If

End Try
Is it possible to force a class to be only used by Using ?
I mean, to help avoid making mistakes in the future.

A quick hack would be a regex replace of Dim [A-Z*][a-z*] As DBHelper
with Using dbhelper as DBHelper over the whole project.

Right ?

Apr 19 '07 #5
Is it possible to force a class to be only used by Using ?
I mean, to help avoid making mistakes in the future.

A quick hack would be a regex replace of Dim [A-Z*][a-z*] As DBHelper
with Using dbhelper as DBHelper over the whole project.

Right ?

Well if you implement IDisposable, you know your connection will dissapear
when the GC collects it, you just don't know when. I would be loathe to
search/replace something like this - rather Find In Files, all instances of
New DBHelper and take it from there. Either use "Using" or use Try/Finally
combination. Take a look at the "Using" keyword either online or in MSDN to
get more information about it before you decided on replacing all instances
of DBHelper in code.

Hope this helps.
Apr 19 '07 #6
On Apr 19, 4:41 am, "lothar.behr... @lollisoft.de"
<lothar.behr... @lollisoft.dewr ote:
Hi,

I have figured out that .NET CLR implements object destruction on the
knowledge of usage of
these objects. My DBHelper class closes the connection when refcount
goes to zero. That happens inside Finalize.

The sample code at the end crashes when I not do a call to getReader
with an empty string.
That is used as a Dummy for ' This object is used until here '
information.

If I use the last getReader line, All is fine.

I came from C++ and expected that GC doesn't touch objects in the same
scope (stack).

This makes me struggling on how to close connections automatically in
Finalize whithout
explicitly set the object to NULL. (In C++ I have smart pointers that
do this for me)

Any Ideas ?

Thanks, Lothar

Public Class DBHelper
Shared conn As SqlClient.SqlCo nnection
Shared refcount As Integer

Public Sub New(ByVal where As String)
refcount = refcount + 1
End Sub

Public Function getReader(ByVal SQL As String) As
SqlClient.SqlDa taReader
Dim mycmd As SqlClient.SqlCo mmand
Dim reader As SqlClient.SqlDa taReader = Nothing

' Return on empty query

If SQL = "" Then
Return Nothing
End If

Try
If conn Is Nothing Then
conn = New
SqlClient.SqlCo nnection("conne ctionstring")
End If
conn.Open()
Catch ex As Exception

' Log some information
conn = Nothing
Return Nothing
End Try

mycmd = conn.CreateComm and
mycmd.CommandTe xt = SQL

Try
reader = mycmd.ExecuteRe ader()
'CommandBehavio r.CloseConnecti on)
Catch ex As Exception

' Log some information
reader = Nothing
Return Nothing
End Try
Return reader
End Function

Protected Overrides Sub Finalize()
If refcount 0 Then
refcount = refcount - 1

If refcount = 0 Then
Try
conn.Close()
conn = Nothing
Catch ex As Exception

End Try
End If
End If
MyBase.Finalize ()
End Sub

Sample:

Public Sub SomeFunction()
Dim dbHelper As DBHelper = New DBHelper()
Dim reader As SqlClient.SqlDa taReader

Dim SQL As String = "SELECT * from SomeTable"
reader = dbHelper.getRea der(SQL)

GC.Collect() ' A
Collect to be appear explicitly or indirectly in

' my code
System.Threadin g.Thread.Sleep( 10) ' Some time
consumption

If Not reader Is Nothing Then
While
reader.Read() ' Crash
Dim SomeField As String = reader.GetValue (0)
End While
End If

'dbHelper.Execu teScalar("") ' Doesn't crash when
this line is uncommented.
End Sub
First, it looks like you're using DBHelper as a mechanism for keeping
a connection open. ADO.NET already supports connection pooling so
DBHelper isn't really buying you anything.

Second, assuming you want to continue using DBHelper, you should be
implementing IDisposable since it is logically holds unmanaged
resources. I don't actually see a problem with the Finalize method
per se, but I get the feeling that it is okay by accident. There are
certain things you cannot do from Finalize. Read the following on
implementing IDisposable correctly.

http://msdn2.microsoft.com/en-us/library/fs2xkftw.aspx

Third, the Finalize is partly responsible for the crash. You said
that by uncommenting the dbHelper.Execut eScalar line the crash no
longer occurs. This is very confusing, but let me try to explain.
The Finalize method is executed when the object is collected the GC.
The GC is *very* aggressive. It can see that dbHelper is no longer
used after the call to getReader. At that point it becomes eligible
for collection immediately. That in turn causes Finalize to run which
closes the SqlConnection and invalidates the SqlDbReader. By
uncommenting the dbHelper.Execut eScalar call the GC sees that it is
used later and so it is not yet available for collection.

Apr 19 '07 #7
lothar.behrens wrote:
<backposted/>

The problem is that in SomeFunction you make an explicit call to the
GC. The GC sees that DBHelper isn't being used anymore and naturally
collects the object, thus triggering your finalize and hence the
demise of the connection.

In other words, you're doing it wrong... =)))))

Why? Because the connection is still being used -- even after DBHelper
has been shutdown: a DataReader *requires* an open connection to
operate. Because DBHelper didn't provide for that, the connection was
already dead when the reader tried to use it. That's why you crashed.

Add an explicit CloseConnection method to your DBHelper, so users know
that it must be closed *after* the connection was used (that is, after
any DataReaders fade out). Or create a ReaderAdapter of some kind,
shielding the actual DataAdapter, to allow for you to correctly track
the connection's life time (this would require that the adapter kept a
reference to the original DBHelper, so to prevent it from a premature
death).

And ditch that refcount. You have no way of controlling that (yes, you
probably do, but it's too much work).

HTH.

Regards,

Branco.
Hi,

I have figured out that .NET CLR implements object destruction on the
knowledge of usage of
these objects. My DBHelper class closes the connection when refcount
goes to zero. That happens inside Finalize.

The sample code at the end crashes when I not do a call to getReader
with an empty string.
That is used as a Dummy for ' This object is used until here '
information.

If I use the last getReader line, All is fine.

I came from C++ and expected that GC doesn't touch objects in the same
scope (stack).

This makes me struggling on how to close connections automatically in
Finalize whithout
explicitly set the object to NULL. (In C++ I have smart pointers that
do this for me)

Any Ideas ?

Thanks, Lothar

Public Class DBHelper
Shared conn As SqlClient.SqlCo nnection
Shared refcount As Integer

Public Sub New(ByVal where As String)
refcount = refcount + 1
End Sub

Public Function getReader(ByVal SQL As String) As
SqlClient.SqlDa taReader
Dim mycmd As SqlClient.SqlCo mmand
Dim reader As SqlClient.SqlDa taReader = Nothing

' Return on empty query

If SQL = "" Then
Return Nothing
End If

Try
If conn Is Nothing Then
conn = New
SqlClient.SqlCo nnection("conne ctionstring")
End If
conn.Open()
Catch ex As Exception

' Log some information
conn = Nothing
Return Nothing
End Try

mycmd = conn.CreateComm and
mycmd.CommandTe xt = SQL

Try
reader = mycmd.ExecuteRe ader()
'CommandBehavio r.CloseConnecti on)
Catch ex As Exception

' Log some information
reader = Nothing
Return Nothing
End Try
Return reader
End Function

Protected Overrides Sub Finalize()
If refcount 0 Then
refcount = refcount - 1

If refcount = 0 Then
Try
conn.Close()
conn = Nothing
Catch ex As Exception

End Try
End If
End If
MyBase.Finalize ()
End Sub

Sample:

Public Sub SomeFunction()
Dim dbHelper As DBHelper = New DBHelper()
Dim reader As SqlClient.SqlDa taReader

Dim SQL As String = "SELECT * from SomeTable"
reader = dbHelper.getRea der(SQL)

GC.Collect() ' A
Collect to be appear explicitly or indirectly in

' my code
System.Threadin g.Thread.Sleep( 10) ' Some time
consumption

If Not reader Is Nothing Then
While
reader.Read() ' Crash
Dim SomeField As String = reader.GetValue (0)
End While
End If

'dbHelper.Execu teScalar("") ' Doesn't crash when
this line is uncommented.
End Sub

Apr 20 '07 #8

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

0
2067
by: Frank Passek | last post by:
Dear all, I've encountered some strange behaviour with PHP (4.3.2) using the CLI-API. When I provide an option in the first line of my script like so: #!/usr/bin/php -c /path_to_my_ini_file and call the script from the (bash-)commandline, PHP seems to ignore this setting. Calling the script with: php -c /path_to_my_ini_file myscript.php
0
1797
by: Phil | last post by:
Hi, I don't understand this strange behaviour: I compile this code : #include <Python.h> #include"Numeric/arrayobject.h" static PyObject *
2
1977
by: Paul Drummond | last post by:
Hi all, I am developing software for Linux Redhat9 and I have noticed some very strange behaviour when throwing exceptions within a shared library. All our exceptions are derived from std::exception. We have a base class which all processes derive from which is always instantiated in main surrounded by a try/catch(std::exception) which catches all exceptions that have not be handled at a higher level. The catch block cleans up and...
3
2363
by: Bruno van Dooren | last post by:
Hi All, i have some (3) different weird pointer problems that have me stumped. i suspect that the compiler behavior is correct because gcc shows the same results. ---------------------------------------------- //example 1: typedef int t_Array; int main(int argc, char* argv)
3
4877
by: Sebastian C. | last post by:
Hello everybody Since I upgraded my Office XP Professional to SP3 I got strange behaviour. Pieces of code which works for 3 years now are suddenly stop to work properly. I have Office XP Developer (SP3 for Office, SP1 for developer, JET40SP8) on Windows XP Home Edition (SP1). The same behaviour occurs on Windows 98 too.
6
2937
by: Edd Dawson | last post by:
Hi. I have a strange problem involving the passing of command line arguments to a C program I'm writing. I tried posting this in comp.programming yesterday but someone kindly suggested that I'd have better luck here. So here goes! My program ignores any command line arguments, or at least it's supposed to. However, when I pass any command line arguments to the program, the behaviour of one of the functions changes mysteriously. I have...
31
2647
by: DeltaOne | last post by:
#include<stdio.h> typedef struct test{ int i; int j; }test; main(){ test var; var.i=10; var.j=20;
4
2101
by: Gotch | last post by:
Hi, I'm getting a very strange behaviour while running a project I've done.... Let's expose it: I've two projects. Both of them use a Form to do some Gui stuff. Other threads pack up messages this way like: public class UiMsg { public enum MsgType { StatusOk }; public MsgType Type;
8
5322
by: Dox33 | last post by:
I ran into a very strange behaviour of raw_input(). I hope somebody can tell me how to fix this. (Or is this a problem in the python source?) I will explain the problem by using 3 examples. (Sorry, long email) The first two examples are behaving normal, the thirth is strange....... I wrote the following flabbergasting code: #-------------------------------------------------------------
20
2245
by: Pilcrow | last post by:
This behavior seems very strange to me, but I imagine that someone will be able to 'explain' it in terms of the famous C standard. -------------------- code ----------------------------------- #include <stdio.h> int main (void) { char xx="abcd"; char * p1 = xx;
0
9687
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
9541
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
10485
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
1
10231
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
9073
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
0
6805
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
5463
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
5585
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
4141
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.