If you work in a language that handles garbage collection completely automatically then you will likely never need to understand the distinction of strong and weak object references. This applies to most scripting languages. However, there is still some crossover — JavaScript ES6 incorporates these as WeakMap and WeakSet.

Your program will allocate memory as it needs it. The vast majority of this allocation will be when creating new objects, something like this:

new MyClass()

The size of all the variables in the class and some extra metadata adds up to a size, let say this is 32 bytes. Once the system allocates the memory it will return an address of where that 32 bytes starts in the overall memory. The address is commonly called a pointerin a lot of languages.

When you no longer need this object, it could be because you explicitly delete/deallocate it or the garbage collector automatically works out that nothing is using the object anymore it will tell the system to free this object based on the original object address.

If your working in a language that doesn’t have atomatic garbage collection you will need to manage the freeing of memory resources manually, like C++:

MyClass *myObject = new MyClass();

// ... do some stuff

delete myObject;

This example is extremely simply and only covers a very small portion of the cases because mostly you will be passing around objects through other functions, across threads and generally have many other parts of your software referring to the same object. This makes it very difficult to know when everyone is finished with the object and safely delete it.

Reference Counting

The garbage collector often works separately and/or in the background of your application, so it has even less insight into when objects no longer in use. Well one very simple way around this is to have a reference count on each of the objects. That is, when an object is assigned to a variable the reference counter on that object is incremented. When the variable falls out of scope the reference counter is decremented, like after a function is finished.

This works works remarkably well as long as the language itself always adheres to a few simple rules and the counter itself is atomic. We can now know at any time if an object is still being held by anyone.

In theory, when this reference counter reaches zero the object can be safely deallocated. This often happens asynchronously or on another garbage collection thread.

The Downside of Reference Counting

Counting references is full proof… until you get in into the realm of objects depending on each other. Let’s consider the class in C++:

class Person

{

public:

string name;

Person *bestFriend; Person(string name);

}

Here is the usage:

Person *spongebob = new Person("Spongebob Squarepants");

Person *patrick = new Person("Patrick Star"); spongebob->bestFriend = patrick;

patrick->bestFriend = spongebob;

When there is no remaining references to either spongebobor patrickthey should be garbage collected. However, because they reference each other they will both have a reference count of 1 and never be deallocated.

Since memory is so cheap and understanding problems can be hard and time consuming this is what ends up happening. Part of the memory your application is consuming will be dead in the sense that it is taking up space and will never be removed.

This is really a problem when your dealing with software that needs to run forever, like a server. Or even some applications that consume a large amount of memory while processing data where leaving millions of dead objects lying around isn’t a good idea.

Weak References

A strong reference is what is explained above and is the default behaviour. A weak reference allows a variable to hold the reference to an object without incrementing the reference counter. If SpongeBob and Patrick had a weak reference to each other then their reference counts would be zero once they were no longer referenced anywhere else and could safely be garbage collected.

Explained another way, SpongeBob no longer has a protection that Patrick will exist, and visa-versa. This creates another problem; what happens if Patrick is deallocated and SpongeBob tries to fetch Patrick’s name? Well, depending on the language your program may crash. It’s important to always check weak references before they are used in case this happens.

Deciding when to use a weak reference can be tricky. As a rule of thumb if you have object that holds a reference to another object of the same type and you know it may be possible for them to hold each other you should use a weak reference to be safe.