473,398 Members | 2,404 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes and contribute your articles to a community of 473,398 developers and data experts.

WeakReferences

11,448 Expert 8TB
Greetings,

introduction

Java is praised (and despised) for its Garbage Collection mechanism. Over the
years and several Java versions the GC mechanism has changed from a simple mark
and sweep collector that caused the early Java programs to freeze temporarily
at moments it shouldn't freeze, to a highly sophisticated multi threaded,
complex 'generation scavenging' collection mechanism that does its work hardly
noticable by the rest of the application or the user.

Memory management in Java is a breeze compared to quite a lot of other programming
languages. Still things can go wrong or run out of hand: memory leaks. To be exact,
it's not really a 'leak' as in e.g. the C program:

Expand|Select|Wrap|Line Numbers
  1. int main() {
  2.    char* p= malloc(42);
  3.    p= malloc(54);
  4. }
  5.  
The first 42 bytes are lost for the posterity because nothing in the program
'points' or 'refers' to it anymore. Not so in Java: a memory leak in Java
means that something still points at a particular piece of memory that holds
an object value, but we don't know which other thing points to it. But we're
sure that something points to it otherwise the Garbage Collector would have
found it.

A Java memory leak is more like 'sticky memory' like chewing gum somewhere under
your shoe: you don't know that it's there but it still is.

If you have accidentally implemented such a misbehaviour in some sort of loop
you can count on it that in the near future an OutOfMemory exception will be
thrown by the Java Virtual Machine and your application will die a miserable death.

A few of the core classes offer the building blocks to do something about the
situation described above. The next paragraphs describe those building blocks.

Weak references

Functionally a WeakReference class is no more than this:

Expand|Select|Wrap|Line Numbers
  1. public class WeakReference<T> {
  2.     private T referent;
  3.     public WeakReference(T referent) { this.referent= referent; }
  4.     public T get() { return referent; }
  5. }
  6.  
Note that this is not the real source code of the WeakReference class, it just
shows how objects of this class behave functionally.

There isn't much functionality really: you can pass a WeakReference any object
of type T at construction time and you can get that object T back later when
you want it again; big deal.

Behind the scene a lot more is going on: when you instantiate a WeakReference
object it registers itself at the Garbage Collector, i.e. it communicates with
the enemy behind our back.

When the Garbage Colector is activated it keeps track of the objects refered to
by all the WeakReferences. If those objects have no other references except for
the references held by the WeakReferences, they're pray in the claws of the
Garbage Collector, i.e. the reference T in the WeakReference object is set to
null and the object is lost for the posterity.

If the T object is refered to by another object not eligible for Garbage Collection
the T object itself will be safe though.

Summarizing: if the only reference to an object is through a WeakReference object,
the object is still eligible for Garbage Collection.

If nothing else refers to a WeakReference object the referent object will only
be safe if something else refers to that referent object directly. The WeakReference
object however is eligible for Garbage Collection. In laymen's terms: WeakReferences
are party poopers: when they are the last reference to an object they cowardly
hand that object over to the Garbage Collector reaper.

Sticky objects

A common scenario for the sticky objects failure happens when Swing objects are
registered as listeners to other objects. When the registered objects are not
needed anymore they are still refered to as listeners by the other objects to
which they were registered.

The nasty thing is that those registered listeners can't know when they're not
needed anymore by the application. It would be tedious for the application to
'manually' remove those listeners when they're not needed anymore, and above,
it would be error prone to do so (programmers are humans and humans are silly
because they make mistakes ever so often).

WeakReferences can be of help here: imagine we do this: instead of registering
a listener to an object we register a WeakReference instead and make the original
listener the referent of the WeakReference object itself. The core of the trick
is that the 'get()' method of the WeakReference object returns null when the
referent object has been Garbage Collected.

For the sake of the example, let's handle ActionListeners that need to be registered
to AbstractButtons.

The AbstractButton contains the implementations for the following methods:

Expand|Select|Wrap|Line Numbers
  1. public void addActionListener(ActionListener listener);
  2. public void removeActionListener(ActionListener listener);
  3.  
Just because an AbstractButton happens to be the base class for everything in
Swing that uses ActionListeners we only have to implement our new class for
the AbstractButton class (three cheers for Swing's design!).

If we want to register our WeakReference as an ActionListener it *has* to be
an ActionListener itself. No problem, here goes:

Expand|Select|Wrap|Line Numbers
  1. public class ActionReference extends WeakReference<ActionListener>
  2.                  implements ActionListener {
  3.     private AbstractButton button;
  4.  
  5.     ActionReference(ActionListener listener, AbstractButton button) {
  6.         super(listener);
  7.         this.button= button;
  8.         button.addActionListener(this);
  9.     }
  10.     public void actionPerformed(ActionEvent event) {
  11.         ActionListener listener= get();
  12.         if (listener == null)
  13.             button.removeActionListener(this);
  14.         else
  15.             listener.actionPerformed(event);
  16.     }
  17. }
  18.  
The constructor takes an AbstractButton and an ActionListener as its parameters.
It keeps track of the button and registers itself as the ActionListener.

When the button fires an event, the ActionReference's actionPerformed method is
invoked. It checks whether or not the real ActionListener has been Garbage
Collected. If so it deregisters itself from the button. If the real listener still exists,
the event is delegated to the real listener just as if it were registered to the
button directly.

For any 'button' and any 'listener' the listener is registered as follows:

Expand|Select|Wrap|Line Numbers
  1. new ActionReference(listener, button);
  2.  
That's all you have to do: when the listener is not needed anymore, our ActionReference
takes care of it by removing itself from the source of the event. Note that I didn't use
the 'getSource()' method from the event object itself. This protects from removing
an ActionListener from the wrong object if the firing of the event was synthesized
by the application itself.

This single little class prevents memory leaks, or 'sticky objects' from the application.
I'm sure you can figure out how to safely handle other types of event firing yourself now.

Hopefully 'till next week and

kind regards,

Jos
Sep 9 '07 #1
0 5512

Sign in to post your reply or Sign up for a free account.

Similar topics

3
by: Yves Dhondt | last post by:
Hello, I've got the following UML design : C | A _____|______ B So 2 objects A and B are connected through a relation C. (For example an employment scheme : person A1 worked for company...
15
by: Alexis | last post by:
Hello, I'm working on a project that uses over a hundred XLSs for transforming xml documents. The project consists of several webservices (IIS) calling a few dlls. This dlls make the business...
7
by: Bryan D. | last post by:
Our application makes extensive use of C#'s event handling mechanism to communicate between classes. A problem has cropped in that it becomes difficult to know for sure that all observers of an...
5
by: Robert Zurer | last post by:
I have a large pool of business objects all referencing one another in various ways. In the client application I want to do something like employee.Delete(); Behind the scenes, I want to...
3
by: Kyle Kaitan | last post by:
I have got two classes, one is Device and the other is Buffer. Every Buffer instance has an associated Device instance, since all Buffers have to be created with Device.CreateBuffer(). Now i want...
6
by: Andrew Hayes | last post by:
Having to remember to unregister for events to prevent a ref count seems to be quite a burden to place on a developer. I have reviewed the WeakMulticastDelegate solution proposed by Xavier Musy...
22
by: Frank | last post by:
Hello, I again ask for help on the next problem, a previous question did not give a solution. The method at the bottom of this message leaves a reference to somethig, as far as I can tell to...
12
by: Bill O | last post by:
Is there a way to determine the number of references to an object? I only need a reference count. Thank you, Bill
9
by: Rob Nicholson | last post by:
Is it possible to trap the creation of a new object and carry out other operations after it's been created? For example, if creating an object of a specific type, then add a reference to a global...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
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,...
0
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...
0
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...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
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,...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

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.