tomcat-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Craig R. McClanahan" <craig...@apache.org>
Subject RE: Memory Usage and Garbage Collection
Date Fri, 03 Jan 2003 19:31:14 GMT


On Fri, 3 Jan 2003, Andreas Probst wrote:

> Hi Craig,
>
> please see intermixed.
>
> On 2 Jan 2003 at 18:18, Craig R. McClanahan wrote:
>
> >
> > Instances can be garbage collected IF AND ONLY IF there are no
> > live references to that object in a static/instance/local
> > variable of some other object that is also in memory.  Only
> > instances that are no longer referenced from other object
> > instances can be recycled.
>
> Please consider the following service() or doGet() or so of a
> servlet:
>
> public void service(ServletRequest request, ServletResponse
> response)
>    throws IOException
> {
>   OtherObject otherObject = new OtherObject();
>   otherObject.doThisAndThat(request, response);
> }
>
> Do I have to place the following
> otherObject = null;
> before the end of service(). Doesn't otherObject be gc-ed
> otherwise? I've never done this.

The "otherObject" reference goes away as soon as the service() method
returns, so you don't have to actually release it yourself.  HOWEVER, you
also need to understand what the constructor of this class did, and what
the doThisAndThat() method did -- it's still possible for that class to
cause memory leaks which you don't know anything about, or possibly can't
do anything about.

>
> What about the object instances, which
> otherObject.doThisAndThat() creates? So far I've thought there
> are no live references if otherObject gets gc-ed.
>

Let's look at a simple case and a complex case:

SIMPLE CASE:  OtherObject has a single instance variable that is
initialized to a String:

  public class OtherObject {
    private String id;
    public OtherObject(String id) {
      this.id = id;
    }
    public String getId() {
      return (this.id);
    }
  }

In this case, the only reference to the String pointed at by id is in this
instance of OtherObject.  Therefore, when you release your reference to
the OtherObject instance and the id string that was passed in (because the
service() method ended), both the OtherObject instance and the foo String
instance are available for GC.

COMPLEX CASE:  OtherObject is a little trickier in its initialization --
it provides a factory pattern method that creates at most one instance of
OtherObject for a particular identifier string.  (This is a *very* common
design pattern -- in fact, Tomcat implements something sort of like this
to ensure that there is at most one instance of each servlet class.)

  public class OtherObject {

    // Private constructor -- use the factory method instead
    private OtherObject(String id) {
      this.id = id;
    }

    // Private instance variable -- one per instance
    private String id;

    // Public getter for the "id" property
    public String getId() {
      return (this.id);
    }

    // Static cache of previously created instances
    private static HashMap cache = new HashMap();

    // Factory method for creating OtherObject instances that
    // guarantees to create only one for a particular id string
    public static OtherObject getOtherObject(String id) {
      synchronized (cache) {
        OtherObject instance = (OtherObject) cache.get(id);
        if (instance == null) {
          instance = new OtherObject(id);
          cache.put(id, instance);
        }
        return (instance);
      }
    }

  }

To use the factory method, you'd say something like this:

    OtherObject otherObject = OtherObject.getOtherObject("idstring");

instead of:

    OtherObject otherObject = new OtherObject("idstring");

and, no matter how many times you call this with the same parameter value,
you'd get the same instance back (basically a singleton pattern with lazy
instantiation).

Now, your "otherObject" reference still goes away at the end of the
service() method, right?

Yep.

So the instance, and it's string, can still be GC'd, right?

Nope.

There is still a live reference to each OtherObject instance sitting in
the static HashMap "cache".  Therefore, this instance cannot be GC'd, even
though *you* have released your own reference to it.  And, if the
OtherObject class is loaded from Tomcat's common/lib directory (for
example), there is no way to ***ever*** GC this instance, because the
public API of the OtherObject class doesn't offer any way to clear the
cache.

Note also that there is nothing that your servlet can do about this -- you
can't even know if its happening without consulting the documentation
and/or the source code for the classes you are calling.  But the code
above will cause a slowly increasing consumption of memory over time
(assuming that you're asking for different id values), even though *you*
are not maintaining any live references to these objects.

Craig


--
To unsubscribe, e-mail:   <mailto:tomcat-user-unsubscribe@jakarta.apache.org>
For additional commands, e-mail: <mailto:tomcat-user-help@jakarta.apache.org>


Mime
View raw message