static block run several times (j2ee, apache tomcat)

J

Jimi Hullegård

The way I understand things, a static block should only run once, when the
class is loaded. But in my test case (se below), it is run several times.

The code:

public class Test
{
private static Test singleton;
private static int hmm = 0;

static
{
System.out.println("--static block");
singleton = Test();
}

private Test()
{
System.out.println("--Creating the Test instance");
System.out.println("--hmm = " + hmm);
hmm++;
}

public static Test getInstance()
{
return singleton;
}
}

public class TestSessionListener implements HttpSessionListener
{
private static Test test;

public TestSessionListener()
{
System.out.println("--new TestSessionListener. this = " + this);
if (test == null)
{
test = Test.getInstance();
}
}
}

All this is in a web application in Apache Tomcat. Now, if I then restart
Apache Tomcat I get the following output:

--new TestSessionListener. this = TestSessionListener@148bd3
--static block
--Creating the Test instance
--hmm = 0
--new TestSessionListener. this = TestSessionListener@1c92535
--static block
--Creating the Test instance
--hmm = 0
--new TestSessionListener. this = TestSessionListener@b0bad7
--static block
--Creating the Test instance
--hmm = 0
--new TestSessionListener. this = TestSessionListener@1126b07
--static block
--Creating the Test instance
--hmm = 0
--new TestSessionListener. this = TestSessionListener@193722c
--static block
--Creating the Test instance
--hmm = 0
--new TestSessionListener. this = TestSessionListener@3e89c3
--static block
--Creating the Test instance
--hmm = 0

My first question is, how come Apache Tomcat create 6 instances of the class
TestSessionListener? That doesn't make any sense to me. But anyway, what
puzzles me even more is the fact that it seems to create 6 instances of the
Test class, and runs the static block 6 times! How is that possible? Is
there 6 java runtime enviroments running at the same time or something? Is
this a bug?

Regards
/Jimi
 
R

Raymond DeCampo

Jimi said:
The way I understand things, a static block should only run once, when the
class is loaded. But in my test case (se below), it is run several times.

The code:

public class Test
{
private static Test singleton;
private static int hmm = 0;

static
{
System.out.println("--static block");
singleton = Test();
}

private Test()
{
System.out.println("--Creating the Test instance");
System.out.println("--hmm = " + hmm);
hmm++;
}

public static Test getInstance()
{
return singleton;
}
}

[snip]


All this is in a web application in Apache Tomcat. Now, if I then restart
Apache Tomcat I get the following output:

[snip]


My first question is, how come Apache Tomcat create 6 instances of the class
TestSessionListener? That doesn't make any sense to me. But anyway, what
puzzles me even more is the fact that it seems to create 6 instances of the
Test class, and runs the static block 6 times! How is that possible? Is
there 6 java runtime enviroments running at the same time or something? Is
this a bug?

This can happen when a class is loaded by multiple classloaders. For
example, within a servlet container, each web application is usually
given a separate classloader. So if you had six web applications, you
might expect to end up with a particular class loaded six different times.

HTH,
Ray
 
J

Joan

Jimi Hullegård said:
The way I understand things, a static block should only run
once, when the
class is loaded. But in my test case (se below), it is run
several times.

The code:
<snip>
Try running it with "java -verbose classname"
This will tell you if the class is being loaded more than one
time.
 
R

Roedy Green

All this is in a web application in Apache Tomcat. Now, if I then restart
Apache Tomcat I get the following output:

Some possibilities. I am just guessing. I don't know what Tomcat
actually does.

1. Tomcat when short on memory serialised all the objects of your
class, and even got rid of the loaded class object containing the
statics. Then it later reconstituted, and did it by rerunning the
static inits.

2. Hotspot detected that no one was using your class anymore and GCed
it. Then you dynamically loaded something that needed it again.

3. Tomcat believed the Java or class file changed or needed
recompilation for some reason. So it reloaded it with a new class
loader.

If I were you, I would tackle possibility (3) first.
 
R

Raymond DeCampo

Roedy said:
3. Tomcat believed the Java or class file changed or needed
recompilation for some reason. So it reloaded it with a new class
loader.

If I were you, I would tackle possibility (3) first.

Good thought Roedy.

Ray
 
J

John Currier

Roedy said:
Some possibilities. I am just guessing. I don't know what Tomcat
actually does.

1. Tomcat when short on memory serialised all the objects of your
class, and even got rid of the loaded class object containing the
statics. Then it later reconstituted, and did it by rerunning the
static inits.

2. Hotspot detected that no one was using your class anymore and GCed
it. Then you dynamically loaded something that needed it again.

3. Tomcat believed the Java or class file changed or needed
recompilation for some reason. So it reloaded it with a new class
loader.

If I were you, I would tackle possibility (3) first.

Possibility 2 is also extremely likely. A few years back I didn't
understand why my transaction manager's static initializer kept
re-running. It was a singleton that nobody kept a reference to so it
would periodically get gc'd. It seemed bizarre, but it makes perfect
sense in hindsight.

John Currier
http://schemaspy.sourceforge.net
 
T

Thomas Hawtin

John said:
Possibility 2 is also extremely likely. A few years back I didn't
understand why my transaction manager's static initializer kept
re-running. It was a singleton that nobody kept a reference to so it
would periodically get gc'd. It seemed bizarre, but it makes perfect
sense in hindsight.

Must have been a while back. Classes are not collected until their
ClassLoader is collectable as well.

IIRC there was a bug where classes could get reloaded, but was fixed way
back in 1.2.

Of course if ClassLoaders are getting unloaded then so will classes.

Tom Hawtin
 
T

tam

This can happen when a class is loaded by multiple classloaders. For
example, within a servlet container, each web application is usually
given a separate classloader. So if you had six web applications, you
might expect to end up with a particular class loaded six different times.

This is almost certainly what's happening...
See
http://jakarta.apache.org/tomcat/tomcat-5.0-doc/class-loader-howto.html
for a discussion of where to install classes so they get loaded only
once
by Tomcat.
Tom McGlynn
 
J

Jimi Hullegård

Thanks for all replies, folks. As you suspected, Raymond, the JVM loaded the
TestSessionListoner class aswell and the Test class six times because there
was six webapps in Tomcat. I removed the other five webapps (jsp-examples
and stuff like that), and the classes are only loaded once. But the thing I
don't understand is, _WHY_ does tomcat/jvm load these classes once for each
webapp? These class files are both specific for this one webapp.

But anyway, thanks for all input. It wasn't a real issue or anything, I was
just curious. And now I have learnt something new.

Regards
/Jimi
 
R

Raymond DeCampo

Jimi said:
Thanks for all replies, folks. As you suspected, Raymond, the JVM loaded the
TestSessionListoner class aswell and the Test class six times because there
was six webapps in Tomcat. I removed the other five webapps (jsp-examples
and stuff like that), and the classes are only loaded once. But the thing I
don't understand is, _WHY_ does tomcat/jvm load these classes once for each
webapp? These class files are both specific for this one webapp.

Depending on how you have libraries arranged, this is the correct
behavior according to the specification. This allows you to have things
like log4j.jar in your webapps with independent configurations that do
not interfere with each other.

If you want the web apps to share the instances of the classes, you have
some options. One way is to package all the web apps in an ear, place
the class in a jar in the root directory with the war files and refer to
the jar in the Class-Path manifest entry of the war files. This may
also work without the ear.

Another, quicker, dirtier way would be to place the classes in a jar
that is in the application servers main classpath. (To find where this
is, look in the documentation for where you would put JDBC drivers. It
is probably just a lib directory somewhere obvious.) Then the classes
will be loaded by the system classloader for the application server.
But anyway, thanks for all input. It wasn't a real issue or anything, I was
just curious. And now I have learnt something new.

If you want to know more, google for some articles on classloaders and J2EE.

HTH,
Ray
 
J

John C. Bollinger

Raymond said:
Jimi Hullegård wrote:
[...]
But the thing I don't understand is, _WHY_ does
tomcat/jvm load these classes once for each webapp? These class files
are both specific for this one webapp.


Depending on how you have libraries arranged, this is the correct
behavior according to the specification. This allows you to have things
like log4j.jar in your webapps with independent configurations that do
not interfere with each other.

Right. The Tomcat docs contain a detailed discussion on where to put
your classes, based on how you want them to be loaded and used.
If you want the web apps to share the instances of the classes, you have
some options. One way is to package all the web apps in an ear, place
the class in a jar in the root directory with the war files and refer to
the jar in the Class-Path manifest entry of the war files. This may
also work without the ear.

Thus transforming a collection of otherwise unrelated webapps into a
single "enterprise application", whose components can then share
classes. That's an interesting solution. However, I don't think it's
the best approach to the OP's problem, as he writes that the classes in
question are specific to just one webapp.
Another, quicker, dirtier way would be to place the classes in a jar
that is in the application servers main classpath. (To find where this
is, look in the documentation for where you would put JDBC drivers. It
is probably just a lib directory somewhere obvious.) Then the classes
will be loaded by the system classloader for the application server.

This is is rarely a good idea. There are special cases where it might
sometimes make sense (e.g. JDBC drivers, as you mentioned), but it
should not be done unless you understand exactly what the implications
are and exactly why you want them.

Given that the classes are specific to one webapp, it is almost certain
that the correct place for them is in that webapp's WEB-INF/lib/ or
WEB-INF/classes/, depending on whether or not they're jarred up.
 
J

John Currier

Thomas said:
Must have been a while back. Classes are not collected until their
ClassLoader is collectable as well.

IIRC there was a bug where classes could get reloaded, but was fixed way
back in 1.2.

Of course if ClassLoaders are getting unloaded then so will classes.

Tom Hawtin

Yes, it probably was on a 1.2 JVM. I assumed that was the expected
behavior. Does that mean that -Xnoclassgc just prevents classloaders
from being unloaded?

John Currier
http://schemaspy.sourceforge.net
 
T

Thomas Hawtin

John said:
Yes, it probably was on a 1.2 JVM. I assumed that was the expected
behavior. Does that mean that -Xnoclassgc just prevents classloaders
from being unloaded?

I would assume so. Having a google turns up
this:

"B.4.1 -Xnoclassgc
"This flag turns off class unloading. Under JDK 1.1.x, this was
important in some circumstances. With Java 2, however, the semantics of
class loading are such that you really don't ever need to use this flag."

http://java.sun.com/docs/books/performance/1st_edition/html/JPAppHotspot.fm.html

I thought interned strings might not be collected, but after a quick
check they do appear to disappear.

Tom Hawtin
 
J

Jimi Hullegård

Raymond DeCampo said:
Depending on how you have libraries arranged, this is the correct behavior
according to the specification. This allows you to have things like
log4j.jar in your webapps with independent configurations that do not
interfere with each other.

Either I missunderstand you now, or you missunderstand what I wrote. The
classes in question was put in the right place, belonging to a _specific_
webapp. But when Tomcat started, it loaded these classes _six_ times when
there were six webapps. Now I only have _one_ webapp, and the classes are
only loaded once.

/Jimi
 
J

John C. Bollinger

Jimi said:
Either I missunderstand you now, or you missunderstand what I wrote. The
classes in question was put in the right place, belonging to a _specific_
webapp. But when Tomcat started, it loaded these classes _six_ times when
there were six webapps. Now I only have _one_ webapp, and the classes are
only loaded once.

I have to suspect that you have either misunderstood where to put a
webapp's own exclusive classes, that you have accidentally
mischaracterized the situation relative the the other webapps' setup and
configuration, or that there is something else going on in your Tomcat
configuration that you have not disclosed (possibly because you're not
aware of it). The alternative is that you have triggered a bug in
Tomcat, which is conceivable, but less likely, than a user error.
 
R

Raymond DeCampo

Jimi said:
Either I missunderstand you now, or you missunderstand what I wrote. The
classes in question was put in the right place, belonging to a _specific_
webapp. But when Tomcat started, it loaded these classes _six_ times when
there were six webapps. Now I only have _one_ webapp, and the classes are
only loaded once.

My misunderstanding; I thought the classes were present in each of the
six webapps.

This may be something to follow up with on the tomcat users mailing
list. (Most Apache projects have one.)

Ray
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top