OSDev.org

The Place to Start for Operating System Developers
It is currently Mon Apr 29, 2024 12:27 pm

All times are UTC - 6 hours




Post new topic Reply to topic  [ 36 posts ]  Go to page Previous  1, 2, 3
Author Message
 Post subject: Re:Newbie Memory Management
PostPosted: Thu Mar 02, 2006 1:25 am 
Offline
Member
Member
User avatar

Joined: Tue Oct 17, 2006 6:06 pm
Posts: 1437
Location: Vancouver, BC, Canada
beyond infinity wrote:
I don't know if java locally instantiated objects are destroyed per se if going outta scope - and if the destructors are called. If dependency lies in the order of how things are to happen, I'd say destroy() ere leaving the function.


There are no destructors in Java, but there are finalizers. Finalizers are fairly evil in that they complicate the implementation of the GC, slow things down, and ought to be unnecessary in the first place. When you create a local object in Java and its only reference goes out of scope, it is not destroyed immediately, but the next time the GC runs there is a good chance that object will be collected. If it has a finalizer, the GC will put it on a queue to be finalized later and it is not collected immediately.

IMO a sane design for a language with garbage collection would mix stack-based objects that have deterministically-invoked destructors with GC'd heap-based objects (that do not have finalizers, ever). That way you could still use C++'s RAII technique to dispose of non-memory resources in a timely and predictable fashion, while leaving pure memory reclamation up to the system. The closest thing I've seen so far is C#'s using block, but it's really just a hack. I think in C++/CLI it's possible to mix the GC and C++ destructor paradigms a lot more. Too bad it's even more complicated and decorated (Foo^ bar; anyone?) than plain old C++...

_________________
Top three reasons why my OS project died:
  1. Too much overtime at work
  2. Got married
  3. My brain got stuck in an infinite loop while trying to design the memory manager
Don't let this happen to you!


Top
 Profile  
 
 Post subject: Re:Newbie Memory Management
PostPosted: Thu Mar 02, 2006 3:18 am 
Offline
Member
Member
User avatar

Joined: Thu Nov 16, 2006 12:01 pm
Posts: 7614
Location: Germany
JoeKayzA wrote:
@Solar: I suspect that this 'memory leak' is actually caused by _native_ code which implements the widget library (there has to be native code somewhere down there), it doesn't have much to do with a broken GC.


To repeat the point I am trying to make: If you're "brought up" to believe your development platform of choice will care for everything, you are going to become someone who is unaware of the fine print. It doesn't really matter whether the problem is the JVM or the widget library or whatever, what matters is that someone who never bothered to think about memory management will have a really hard time finding bugs like that.

Or, to put it differently: I'd employ a C++-coder-gone-Java without any hesitation. I would interview a Java-coder-gone-C++ very closely before allowing him to work in my project.

_________________
Every good solution is obvious once you've found it.


Top
 Profile  
 
 Post subject: Re:Newbie Memory Management
PostPosted: Thu Mar 02, 2006 4:10 am 
Offline
Member
Member
User avatar

Joined: Wed Oct 18, 2006 2:31 am
Posts: 5964
Location: In a galaxy, far, far away
Colonel Kernel wrote:
IIRC, event handlers in Java are just objects that implement event handling interfaces, so the sequence would go something like this:
  • Create an object A that will fire events.
  • Create an object B that will handle events.
  • Register B with A. At this point, your code refers to A and B, and A refers to B as well.
  • Release A (and probably B). This really means giving up your reference to it, so it is no longer reachable by any root.
  • At this point, A refers to B, but nothing else refers to A, and nothing else refers to B.
I see no reason why A and B would not be collected in this case. Even if A and B point at each other, GCs have no trouble dealing with cycles (unless you're using reference counting).


Iigc, the case Solar was talking about implies that A is a static object handling the GUI. It doesn't necessarily needs to be native.

Just let's suppose that upon Gui.RegisterEvent(Gui.MouseMovedEvent, B); the static object GUI adds B (or more likely, an EventHandlerObject referencing B) into a HashTable so that it can retrieve who's interested into MouseMoved event later ...

If you now remove all references to B in your program but forget to call Gui.UnregisterEvents(B) before this, then there's a dangling reference to B in the GUI's hashtable (making B never collected), even if the window that contains B has been released an is now inactive...

The natural place where I would have called UnregisterEvents(this) would have the destructor of B (that is, if B gets out of scope, unregister everything related to B)... which would fail to work with a GC, of course.

And about "finalize()" being evil, i once had a situation where "finalize()" was very handy: for objects that stores logs. I wanted all the per-object-history written back in a file after the object's life was over, but the framework (being Java-minded) didn't provide a way to say "object X is now out of scope and won't ever be called" so all i could rely on was the "finalize()", or i might miss lately introduced entries.

No need to say that it indeed started a war between me and the GC :P

_________________
Image May the source be with you.


Top
 Profile  
 
 Post subject: Re:Newbie Memory Management
PostPosted: Thu Mar 02, 2006 4:53 am 
Offline
Member
Member
User avatar

Joined: Thu Nov 16, 2006 12:01 pm
Posts: 7614
Location: Germany
Colonel Kernel wrote:
There are no destructors in Java, but there are finalizers. Finalizers are fairly evil in that they complicate the implementation of the GC, slow things down, and ought to be unnecessary in the first place. When you create a local object in Java and its only reference goes out of scope, it is not destroyed immediately, but the next time the GC runs there is a good chance that object will be collected. If it has a finalizer, the GC will put it on a queue to be finalized later and it is not collected immediately.


Finalizers in Java are not fairly evil, they are evil.

One, any exception thrown by them is ignored, the finalization of the object halted. Means: You just leaked memory, no way to recover. I agree that C++ is only marginally more friendly here - if a destructor throws an exception while another exception is currently rolled back, your program calls [tt]terminate()[/tt]. But that can be caught and handled.

Two, there is no guarantee that your [tt]finalize()[/tt] function will ever be called, not even when the JVM terminates. It is called "when and if" the GC touches the object for collecting. Which might be immediately, later, or never.

And as for performance... every Java [tt]Object[/tt] does have a finalize() function, which simply returns while doing nothing. One more function call to execute for each object finalized. (Compare this with a C++ object only having native member types - "destruction" is a nop in this case.)

_________________
Every good solution is obvious once you've found it.


Top
 Profile  
 
 Post subject: Re:Newbie Memory Management
PostPosted: Thu Mar 02, 2006 9:06 am 
Offline
Member
Member
User avatar

Joined: Tue Oct 17, 2006 6:06 pm
Posts: 1437
Location: Vancouver, BC, Canada
Solar wrote:
Or, to put it differently: I'd employ a C++-coder-gone-Java without any hesitation. I would interview a Java-coder-gone-C++ very closely before allowing him to work in my project.


I absolutely agree. My company's recruiting process is set up specifically to avoid this problem. :)

Pype.Clicker wrote:
Iigc, the case Solar was talking about implies that A is a static object handling the GUI. It doesn't necessarily needs to be native.

Just let's suppose that upon Gui.RegisterEvent(Gui.MouseMovedEvent, B); the static object GUI adds B (or more likely, an EventHandlerObject referencing B) into a HashTable so that it can retrieve who's interested into MouseMoved event later ...

If you now remove all references to B in your program but forget to call Gui.UnregisterEvents(B) before this, then there's a dangling reference to B in the GUI's hashtable (making B never collected), even if the window that contains B has been released an is now inactive...

The natural place where I would have called UnregisterEvents(this) would have the destructor of B (that is, if B gets out of scope, unregister everything related to B)... which would fail to work with a GC, of course.


Ahh... I get it now. This is actually "unintentional object retention", not a memory leak per se. The problem is caused by the Gui's scope -- it is a long-lived object referring to short-lived objects.

The solution to this would be for Gui to use weak references to event handlers instead of strong references. That way, Gui's reference to B doesn't prevent B from being garbage collected. Whenever the event occurs, Gui would check its weak reference to B to see if it's still valid. If so, the event is delivered; if not, it is safe for Gui to remove B from its hashtable. In this case, the designers of Gui must have their thinking caps on. :)

Solar wrote:
Finalizers in Java are not fairly evil, they are evil.


Heh, ok. I was being charitable for cases like Pype's (although in truth Pype, writing to a log file in a finalizer scares the willies out of me...)

Quote:
And as for performance... every Java [tt]Object[/tt] does have a finalize() function, which simply returns while doing nothing. One more function call to execute for each object finalized. (Compare this with a C++ object only having native member types - "destruction" is a nop in this case.)


My teammate and I were just dealing with this issue yesterday (we're doing a lot of Java/C++ integration via the JNI this week). Even though every Java object inherits "finalize()" from java.lang.Object, only those objects that actually override finalize() are put on the finalization queue by the GC. The performance would just be too terrible otherwise.

_________________
Top three reasons why my OS project died:
  1. Too much overtime at work
  2. Got married
  3. My brain got stuck in an infinite loop while trying to design the memory manager
Don't let this happen to you!


Top
 Profile  
 
 Post subject: Re:Newbie Memory Management
PostPosted: Thu Mar 02, 2006 10:07 am 
Offline
Member
Member
User avatar

Joined: Thu Nov 16, 2006 12:01 pm
Posts: 7614
Location: Germany
Colonel Kernel wrote:
...only those objects that actually override finalize() are put on the finalization queue by the GC. The performance would just be too terrible otherwise.


Ahhhhh... undermining their own specs, are they? :-D

_________________
Every good solution is obvious once you've found it.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 36 posts ]  Go to page Previous  1, 2, 3

All times are UTC - 6 hours


Who is online

Users browsing this forum: Bing [Bot], Google [Bot] and 9 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group