Managing Object Lifetimes

April 15th, 2009 · 13 Comments ·

There is a myth out there that creating objects is expensive. The result of this is that a lot of applications have objects whose lifetime is too long. Let’s take a web app for example. Most web-apps I have seen have too many long lived objects and not enough request scope objects, which has implication on how data flows through the application. A web app has at least three scopes: application, session and request scope. These scopes are in decreasing lifetime and most of the time they do not overlap (ie the request scoped objects die, before the session objects can die).

I believe objects should only maintain references to other objects that are equal or longer-lived. In other words, a request can know about session, but it is not a good idea for the session to know about a request. (When I say ‘know’, I mean that it does not have field reference to request, it can have temporary reference through the stack, i.e. method parameter.) The way a long lived object gets a hold of a short lived object is through the stack (passed in through a method parameter).We could generalize this rule to say: Pass in objects of equal and greater lifetime through the constructor and objects of shorter lifetime through the stack.

Now the interesting part is what happens when you start to break this rule. There are two ways to break this rule, lets look at them in turn.

When this rule is reversed (passing short lived objects into a long lived object constructor. i.e. session knows about request) you have a recipe for bugs, since now the garbage-collector will not be able to clean up the objects which are clearly out of scope. There is not much you can do with a request object after the http connection is closed. I see this mistake often, and usually developers solve this through some kind a clean up code. Recently, for example, I came across a game of GO which had a App and the Game class. Now App is lifetime of the application but Game is only for the duration of the game. In the code every time the user wanted to play a new game the App had to go through a cleaning process for a Game object, which was a source of errors. Your first game would behave right but your second game may not. Solution is to simply throw away the Game and instantiate a new one.  Now the App is responsible for instantiation of the Game object but the App does not keep a reference to the Game object (beyond the local reference on the stack.)

More common violation is to not have an appropriate life time object in the first place. For example let’s say that you have a web app and you don’t have any classes which are meant to be request scope, such as a Servlet. A servlet is application scoped, as a result, you cannot inject the request/response into the constructor, instead you have to pass them through a stack, which is exactly what happens. Now not all code is in your servlet, therefore your servlet needs to collaborate with other objects, but most of them are application scoped as well. Now let’s say that you have three application scoped objects A, B and C, such that A calls B, B calls C and A does not know about C directly (i.e. A->B->C). Let’s say that C needs the http cookie. The only way for me to get the cookie into C from my servlet is to pass it in as an argument to A, which than passes it to B, which than passes it to C. Sooner or later you will realize that this is a real pain, since every time C needs a new object reference you have to modify all of these unrelated objects. Therefore you will create a context object which knows about cookie and all of the other objects and you will be proud of yourself how clever you are. But a context is solving the wrong problem. The real problem is that C’s lifetime is wrong. If C’s lifetime would be that of cookie (request scope) than the Servlet could just pass it in directly like this:

HttpRequest request = ...;
C c = new C(request.getCookie());
B b = new B(c);
A a = new A(b);
a.doWork();

Now this is great since A and B are no longer involved in the process of passing along the cookie. After all neither A nor B cares about the cookie. It also means that if at some later point in time C needs additional object such as request-path C can just ask for it in the constructor without having to change anything in A nor B.

Servlet becomes a place where the long lived object (servlet) meets short lived object (our ABC object graph). This means that whenever you have to cross the object boundary in reverse you need a factory, which is what our servlet does.

Therefore, whenever you get into situation when you have to pass objects through many layers, or that you create a context and than pass the context through the layers your layers are probably long lived and need to have their lifetime adjusted. You can generalize this and say that: Whenever a class has a reference to another object but does not directly dispatch methods on that object, than the collaborator which needs the object is of wrong lifetime.

Tags: Uncategorized

13 responses so far ↓

  • Giorgio Sironi // Apr 16, 2009 at 2:21 am

    > Now I believe that each object should have reference to other objects
    whose lifetime is equal or shorter to the object. > In other words, a
    request can know about session, but it is not a good idea for the
    session to know about a request.It is “equal or longer” I guess…

  • Jonathan Hartley // Apr 16, 2009 at 5:45 am

    Brilliant article, something thanks!

    The sentence beginning para 2 is ambiguous:

    >> Now I believe that each object should have
    >> reference to other objects whose lifetime is
    >> equal or shorter to the object.

    This says to me the opposite of what I think you intend. How about replacing it with something like:

    >> I believe objects should only maintain references to other objects that are longer-lived.

    Or have I misunderstood again? :-)

  • Jonathan Hartley // Apr 16, 2009 at 5:46 am

    ‘something thanks’ == ‘This is something I haven’t thought about at all before, but makes brilliant sense – Thanks!’

  • misko // Apr 16, 2009 at 6:15 am

    @Jonathan,

    Thanks, I updated the text…

  • Mat Noguchi // Apr 17, 2009 at 9:45 am

    Do event handlers fall outside this rule? I’m trying to think of how to have a long lived object publish events without having a reference to shorter lived objects…

    MSN

  • Przemek // Apr 23, 2009 at 5:29 am

    @MatI don’t know what rule says about it, but I learned one thing: you’d better be careful with publishing events to shorter-lived objects or their lifetime will exceed your expectations ;) In practice I’ve used two techniques: one was to carefully unregister my short-lived listeners at the end of their life. Second was to use weak references to the listeners from the event publisher.

  • igorbrejc.net » Fresh Catch For May 5th // May 5, 2009 at 12:03 am

    [...] Managing Object Lifetimes [...]

  • David V. Corbin // May 29, 2009 at 8:04 am

    An excellent article…

    One “Quibble”..There is no problem per se with passing a short lived to a long lived constructor parameter. It is NO different than passing it as a parameter to ANY method.

    The problem (which I believe was your intent) was keeping a reference to a shorter lived that exceeds the scope of a single call from the short lived into the long lived.

  • misko // May 29, 2009 at 7:02 pm

    @David,

    passing a short lived object through a constructor is really confusing. Since you either have a bug because you are not clearing it or you will clear the reference later which implies that you only need the object temporarily. If you need something temporarily than that suggest that your lifetime is longer than it should be or you only need it in constructor which implies that you are doing work in constructor. I like to declare all of the fields which I get through constructor as final. Which is a hint to the reader that they are not changing and are needed for the duration of the object lifetime. On the other hand passing it in through stack implies that you will probably not keep a reference as it is a temporary thing you need to get the work done.

  • David V. Corbin // Jul 27, 2009 at 12:25 pm

    Misko.. [Yes I know it has been two months]

    Consider a class S which has a string key.

    You are designing a class L which requires a valid key to an S object.

    You can design L’s constructor to take a string, but then you have the overhead of validating it.

    Or, you can have the constructor take an instance of S and simple store (in a readonly field) the Key (which is already valid since it came from an existing S)

    How is S is short lived, and L is long lived (funny how that worked out), then you have the exact scenario I was referring to.

    When the constructor exits, there are no referneces between the Short Lived and Long Lives objects in either direction. Yes by passing the short to the long as only a stack transaction, the goals are fully achieved with no overhead.

  • mciasco // Sep 21, 2009 at 6:22 am

    @David
    This is not a good example, cause L’s constructor needs a parameter “key” of string type. Parameters such like that are not injectable cause a factory for L does not know which string have to be passed to the constructor during the real build process of L.

    However, the question is: why should I pass a parameter in a constructor if it is used as a temporary object inside of it, probably just to get some other object from that parameter? This is a clear violation of the Law of the Demeter. If L needs a string-key to be able to be bound to a particular instance of S, why don’t ask for S directly in its constructor?

  • Frank // Aug 19, 2010 at 1:24 am

    Great article!

    > Whenever a class has a reference to another object but does not directly dispatch methods on that object, than the collaborator which needs the object is of wrong lifetime.

    Couldn’t there be another reason than wrong lifetime? I think this symptom (isn’t it a violation to LoD in the first place?) could also indicate a missing responsibility that wants to be invented.

    Either way. It’s a smell. Do you know of static analysis tools that reveal that smell?

  • misko // Aug 19, 2010 at 10:29 pm

    @frank, no I don’t know of any tool.

Leave a Comment