Problems with Garbage Collection.

  • Thread starter Thread starter Mark Gillespie
  • Start date Start date
M

Mark Gillespie

I have a class that launches a process (amongst other things). I keep
track of the process handle, and just prior to the obejct being destroyed
by the garbage collector, I want to kill that process. Basically, if some
exits my application, I don't want any stray background applications
running created by instances of my class.

I tried calling the kill() method on the process handle in the class's
destructor, but the handle must have been destroyed already, as it's not a
valid handle any more (even thou the now orphaned process is still
running).

How can I achieve what I want to do? Is there a way of trapping a even
just prior ro garbage colection?

As you may have guessed, I am quite new to this C# stuff.. :-)

Thanks for any suggestions...
 
As you have no control over when garbage collection gets called, this
is not the proper way to do this. Instead you need to have a
methedology inside your program to make sure that all the needed
cleanup is performed.
 
just a thought, and it's probably wrong - but did you look into making
that handle static, and then on Application.ApplicationExit within your
Main try destroying it?
 
As you have no control over when garbage collection gets called, this
is not the proper way to do this. Instead you need to have a
methedology inside your program to make sure that all the needed
cleanup is performed.


Like on application close, rather than object deletion? Any examples of
how I should consider doing this?
 
A process handle is a system wide opaque value maintained by the OS, the
handle stays valid for as long as the process exists, the GC has no way to
invalidate such and handle, could you try to check the value of the handle
before you issue the kill?.

Willy.
 
A process handle is a system wide opaque value maintained by the OS, the
handle stays valid for as long as the process exists, the GC has no way
to
invalidate such and handle, could you try to check the value of the
handle
before you issue the kill?.

Willy.

It's not the handle that invalid, it's the variable that stores the handle
that's been garbage collected.
 
How can that be, you call Kill on a reference to an instance of the Process
class, if the instance is still valid (not GC'd) it's member 'Handle' should
be valid too, if the instance is invalid, you can't call a method on it.

Could you post your code or at least a small but complete sample that
illustrates the issue?

Willy.
 
Willy said:
How can that be, you call Kill on a reference to an instance of the
Process class, if the instance is still valid (not GC'd) it's member
'Handle' should be valid too, if the instance is invalid, you can't
call a method on it.

From the OPs original message:

<quote>
I tried calling the kill() method on the process handle in the class's
destructor, but the handle must have been destroyed already, as it's not
a
valid handle any more (even thou the now orphaned process is still
running).
</quote>

I assume that by "destructor" he means the finalizer of his class. If
so, then it's no wonder he's running into problems. What the OP does
violates the rule that no finalizer should access objects that
themselves have a non-trivial finalizer since the order of finalization
is arbitrary under .NET. Process derives from Component, which has a
finalizer calling its protected Dispose( bool ) method. This in turn is
overridden in Process. The override closes the internal handle and sets
it to IntPtr.Zero...

Regards,
 
From the OPs original message:

<quote>
I tried calling the kill() method on the process handle in the class's
destructor, but the handle must have been destroyed already, as it's not
a
valid handle any more (even thou the now orphaned process is still
running).
</quote>

I assume that by "destructor" he means the finalizer of his class. If
so, then it's no wonder he's running into problems. What the OP does
violates the rule that no finalizer should access objects that
themselves have a non-trivial finalizer since the order of finalization
is arbitrary under .NET. Process derives from Component, which has a
finalizer calling its protected Dispose( bool ) method. This in turn is
overridden in Process. The override closes the internal handle and sets
it to IntPtr.Zero...

Regards,


I found a way around it now, that seems to be working well.
 
This is a valid assumption on v1.1 of the framework, but I would like to see
some code ;-).

Willy.
 
Willy said:
This is a valid assumption on v1.1 of the framework,

Yep, 2.0 would be able to deal with this kind of usage so I assumed the
OP is talking about 1.1, the currently released version.
but I would like
to see some code ;-).

What code, exactly?

Regards,
 
Great, mind to tell the community how you did?

Willy.


As long as you all promise not to laugh, or flame me to hell, or tut that
newbies should not be let near a compiler... :-)

I made the varible that stored the reference to the process handle public,
and then on app exit, I checked each one in a foreach loop to ensure that
if they were still running, that I called kill() on them (in the apps
Closing method).

Not sure if this is totally wrong, but it seems to work reliably, without
any apparent problems. I would have rather the class looked after it's
own processes, but it's not to be alas...
 
Andreas Huber said:
Yep, 2.0 would be able to deal with this kind of usage so I assumed the OP
is talking about 1.1, the currently released version.


What code, exactly?

The OP's code, or something that illustrates the issue, else we might be
starting to make wrong assumptions, like assuming that the posters are
talking about v1.1 for instance, look at how many post v2.0 issues, they
don't care that it's not currently released.

Willy.
 
Mark Gillespie said:
As long as you all promise not to laugh, or flame me to hell, or tut that
newbies should not be let near a compiler... :-)

I made the varible that stored the reference to the process handle public,
and then on app exit, I checked each one in a foreach loop to ensure that
if they were still running, that I called kill() on them (in the apps
Closing method).

Not sure if this is totally wrong, but it seems to work reliably, without
any apparent problems. I would have rather the class looked after it's
own processes, but it's not to be alas...

I would never laugh or flame somebody to hell, newbie or not. That said,
there is something that I don't get, you are keeping a variable that holds
the process handle, but in your Closing method you have to call Kill on the
Process instance reference, right? So, why don't you simply call Kill and
catch the SystemException that gets thrown when you kill a no longer
existing process?

Willy.
 
Mark Gillespie wrote:
[snip]
Not sure if this is totally wrong, but it seems to work reliably,
without any apparent problems. I would have rather the class looked
after it's own processes, but it's not to be alas...

With a trick you can still let the class look after the Process objects
it owns. As mentioned, you cannot access non-static Process fields from
a finalizer but you can access Process objects that reside in a
collection that is declared static. The folloing code (untested)
outlines the idea, sprinkle with lock statements as necessary:

public class ProcessOwner
{
readonly static Hashtable processes = new Hashtable();
static int currentId;

readonly int id;

public ProcessOwner()
{
this.id = currentId++;
processes[ this.id ] = new Process( /* ... */ );
}

~ProcessOwner()
{
// When the CLR is shutting down (e.g. Main() has exited), objects
in static
// collections are also finalized, so we can only do this during
normal
// operation.
if ( !Environment.HasShutdownStarted )
{
( (Process) processes[ this.id ] ).Kill();
}
}
}

Now, in Main(), you add the following code:

static void Main()
{
try
{
// Normal Main() code
}
finally
{
GC.Collect();
GC.WaitForPendingFinalizers();
}
}

Of course, this only works if no ProcessOwner objects are directly or
indirectly referenced from root references when the finally block
executes.

Regards,
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Back
Top