A very stubborn private static member

S

steve.chambers

Help!!!

I'm testing a class that has a particularly stubborn private static
member variable. This variable is initialised in the class's
constructor like this:

myClass {
private static myStaticVariable = null;

// Constructor
public myClass() {
// Initialise private static variable
if (myStaticVariable == null) {
myStaticVariable = something;
}
}
...
}

and then as I understand it the private static member will never change
until all instances of the class are destroyed.

But at various points in my test I need to make sure that the private
static variable *does* get reinitialised to 'something' in the
constructor when a new object is created (I won't bore you with why I
need to do this). I'm not allowed to redesign the class so I can't add
a "setter" method for this variable or make it public. So what I really
need to do is make sure that all previously use objects of this are
garbage collected...

....So in my test I've tried putting in a couple of "Thread.sleep()"s
and a couple of "System.gc()"s in order to give Java plenty of time to
garbage collect but it just doesn't seem to take the hint - once
myStaticVariable has been initialised it seems very reluctant to
uninitialise itself!

Can anyone help with this or is it just one of those Java annoyances
that can't be fixed??

Thanks for any help & suggestions...

Cheers, Steve
 
A

Andrea Desole

Help!!!

I'm testing a class that has a particularly stubborn private static
member variable. This variable is initialised in the class's
constructor like this:

myClass {
private static myStaticVariable = null;

// Constructor
public myClass() {
// Initialise private static variable
if (myStaticVariable == null) {
myStaticVariable = something;
}
}
...
}

and then as I understand it the private static member will never change
until all instances of the class are destroyed.

mmm, I actually think the private static member will never change as
long as the JVM runs

But at various points in my test I need to make sure that the private
static variable *does* get reinitialised to 'something' in the
constructor when a new object is created (I won't bore you with why I
need to do this). I'm not allowed to redesign the class so I can't add
a "setter" method for this variable or make it public. So what I really
need to do is make sure that all previously use objects of this are
garbage collected...

and how can you be so sure that all the objects are not referenced and
are eligible for garbage collection?

...So in my test I've tried putting in a couple of "Thread.sleep()"s
and a couple of "System.gc()"s in order to give Java plenty of time to
garbage collect but it just doesn't seem to take the hint - once
myStaticVariable has been initialised it seems very reluctant to
uninitialise itself!

One more thing: you can't be 100% that your objects are garbage
collected. Even if you call System.gc()
Can anyone help with this or is it just one of those Java annoyances
that can't be fixed??

well, the real annoyance is that you have a private static member, and
you are trying to change it without any setter and without changing the
class. I don't know why you are trying to do this, but that doesn't look
a normal situation to me
Anyway, I think you should be able to do that using reflection. But
that's more a hack. Looks like the real problem is another one.
 
S

steve.chambers

Thanks for the quick reply Andrea! I agree that perhaps a setter should
have been provided but in this case it hasn't and I've been asked to
write a test for a class that I'm not allowed to change. In order to
achieve a good level of statement coverage I need this variable to be
reinitialised several times. Trying to keep the discussion general and
pure about Java rather than specifics so I won't go into why here.)

Of course one way to do it would be write multiple tests that are run
separately but I'd rather not do that if I can help it. Interesting
that you say the the private static member will never change as long as
the JVM runs as this is what I'm finding. But I thought if all the
objects are no longer referenced (and yes I am sure about this) and I
wait long enough it would be reset. But this is not what I'm finding -
as you say, it just persists!

Perhaps the reflection "hack" might be the best way forward but I'm not
sure about how to do this either, will look into this but if you have
any further advice on how to do it please let me know.

Cheers,
Steve
 
A

Andrea Desole

Perhaps the reflection "hack" might be the best way forward but I'm not
sure about how to do this either, will look into this but if you have
any further advice on how to do it please let me know.

try this:

- call getClass() on your MyClass object to get the Class object
- call getField( "myStaticVariable" ) on the Class object to get your
static field
- call set( null, myNewInstance ) to set the value

I never used reflection on members, let alone private and static, but
that should do the job
 
P

Patricia Shanahan

and then as I understand it the private static member will never change
until all instances of the class are destroyed.

The condition is actually a lot stronger than that. As I understand the
code, the only condition for changing from non-null to another value is
when the class is loaded. That will happen only once in the program run
if it is loaded in the normal way. See the JLS, "12.7 Unloading of
Classes and Interfaces", at
http://java.sun.com/docs/books/jls/second_edition/html/execution.doc.html#74294

"A class or interface may be unloaded if and only if its defining class
loader may be reclaimed by the garbage collector as discussed in §12.6.
Classes and interfaces loaded by the bootstrap loader may not be unloaded."

You have several choices:

1. Add a setter.

2. Use reflection to make the variable null, as Andrea suggested. This
is probably the best option, because it is the simplest option that
avoids changing the original program.

3. Load the class, in each test, using a ClassLoader created for the test.

4. Do multiple test runs, each testing the transition from null to
non-null once.

Patricia
 
C

Chris Uppal

and then as I understand it the private static member will never change
until all instances of the class are destroyed.

No, your understanding is wrong. The simple answer is that the static member
will keep the last value that was assigned to it until the program exits.

The slightly more complicated answer (which is maybe what you were thinking of)
is that /if/ the class is garbage collected, and subsequently re-loaded, then
the static member will not be preserved over that unload-load pair. However
it's important to realise that unless you have designed your application
specifically in order to allow classes to be GCed, then this will never happen.

The rules are that no class is GCed unless its owning classloader is also
eligible for GC. That will only be the case if (slightly simplified):
the classloader itself is not referred to anywhere
none of the classes that it loaded are referred to anywhere
none of the classes it loaded have any instances
a few other minor conditions are met.
Those conditions are very unlikely to be satisfied unless you have designed
your overall application to make it possible. In particular, no class loaded
either by the primordial classloader or by the application classloader can
/ever/ be eligible for GC.

-- chris
 
A

Andrea Desole

Chris said:
The slightly more complicated answer (which is maybe what you were thinking of)
is that /if/ the class is garbage collected, and subsequently re-loaded, then
the static member will not be preserved over that unload-load pair. However
it's important to realise that unless you have designed your application
specifically in order to allow classes to be GCed, then this will never happen.

The rules are that no class is GCed unless its owning classloader is also
eligible for GC. That will only be the case if (slightly simplified):
the classloader itself is not referred to anywhere
none of the classes that it loaded are referred to anywhere
none of the classes it loaded have any instances
a few other minor conditions are met.
Those conditions are very unlikely to be satisfied unless you have designed
your overall application to make it possible. In particular, no class loaded
either by the primordial classloader or by the application classloader can
/ever/ be eligible for GC.

this is interesting. Do you have any reference?
 
T

Thomas Hawtin

I'm testing a class that has a particularly stubborn private static
member variable. This variable is initialised in the class's
constructor like this:

myClass {
private static myStaticVariable = null;

// Constructor
public myClass() {
// Initialise private static variable
if (myStaticVariable == null) {
myStaticVariable = something;
}
}
...
}

Why on earth are you doing that? Why not just initialise static members
in the static initialiser?
and then as I understand it the private static member will never change
until all instances of the class are destroyed.

That's not a particularly useful way to look at. Objects don't get
destructed in Java. They just become unreferenced.

The code as presented could initialise the variable more than once if
called from multiple threads, as there is no attempt at safety. If you
are testing the code to see if it is buggy, I can tell you without all
that effort, it is.

In the case of classes, they have a reference to the class loader that
loaded them. There is also a strong reference from the class loader to
the class. So unless you monkey about with class loaders your class will
never "unload".
But at various points in my test I need to make sure that the private
static variable *does* get reinitialised to 'something' in the
constructor when a new object is created (I won't bore you with why I
need to do this). I'm not allowed to redesign the class so I can't add
a "setter" method for this variable or make it public. So what I really
need to do is make sure that all previously use objects of this are
garbage collected...

Classes that mutate static members are inherently detestable. If you
have to deal with very poor code, then your choices are either
reflection with a high dependency on your tested code or playing silly
buggers with class loaders.
...So in my test I've tried putting in a couple of "Thread.sleep()"s
and a couple of "System.gc()"s in order to give Java plenty of time to
garbage collect but it just doesn't seem to take the hint - once
myStaticVariable has been initialised it seems very reluctant to
uninitialise itself!

Guaranteeing that you have done a thorough GC is difficult. I can't
honestly remember the variations of what System.gc does in different JRE
versions. I think on Sun's JREs from 1.3 it does a pretty thorough job.
IIRC, 1.2 ignored it most of the time.

Normally a GC caused by allocation will just clear the eden generation.
Clearing class data or tenured objects is more difficult. Finalisers
stop immediate collection. Really you need to be filling the memory with
referenced objects to be sure.

Tom Hawtin
 
S

steve.chambers

Thanks for all the replies. I tried the reflection method but it turns
out that getField() doesn't allow access to private members. Checked in
the JDK, which says:

"Returns a Field object that reflects the specified public member field
of the class or interface represented by this Class object. The name
parameter is a String specifying the simple name of the desired field."

So it seems to not allow access to private members. A few others seemed
to think reflection should work, can anyone give a working example? As
I say it is a hack and I agree with the comments about the code itself
not exactly being a good design but please bear in mind I have no
control over this code or authority to change it so I don't think I
have much choice to make the test work (all the customer is bothered
about is seeing 100% statement coverage!!)
 
T

Thomas Hawtin

Thanks for all the replies. I tried the reflection method but it turns
out that getField() doesn't allow access to private members. Checked in
the JDK, which says:

getDeclaredField is what you want. And possible setAccessible.

Tom Hawtin
 
P

Patricia Shanahan

Andrea said:
There is still something I don't understand. I see a relationship
between class unloading and class loder gc-eligibility (is it what you
mean?), not between class gc-eligibility and class loader gc-eligibility.
Am I missing something?

As long as a Class is reachable, its ClassLoader is also reachable
through the Class's getClassLoader method.

Being unreachable is a necessary, but not sufficient, condition for
garbage collection. See section 12.6.1 of the JLS for the details.

Patricia
 
I

Ingo R. Homann

Hi,

Thanks for all the replies. I tried the reflection method but it turns
out that getField() doesn't allow access to private members. Checked in
the JDK, which says:

"Returns a Field object that reflects the specified public member field
of the class or interface represented by this Class object. The name
parameter is a String specifying the simple name of the desired field."

So it seems to not allow access to private members. A few others seemed
to think reflection should work, can anyone give a working example?

You may call field.setAccessible(true); first!
As
I say it is a hack and I agree with the comments about the code itself
not exactly being a good design

"not exactly"... yes! ;-)
but please bear in mind I have no
control over this code or authority to change it so I don't think I
have much choice to make the test work (all the customer is bothered
about is seeing 100% statement coverage!!)

You may tell your customer that "statement coverage" is not a very good
measure for a test. I've read something about different coverage
measures in the last days (unfortunately, that was a german article) and
there were mentioned some other, better coverage types ("complexity
coverage", "path coverage" or something like that (*)). Unfortunately,
most tools do not provide anything other than statement coverage and its
derivats like block coverage and method coverage...

Ciao,
Ingo

(*) Consider the following:

String sql="select * from table";
if(orderByCol1) {
sql+=" order by col1";
}
if(orderByCol2) {
sql+=" order by col2";
}
execute(sql);

Now if your test calls this code one time with
orderByCol1==true&&orderByCol2==false
and another time with
orderByCol1==false&&orderByCol2==true
then all your code is covered 100% which seems good.

However, if you call it with
orderByCol1==true&&orderByCol2==true
there will be an SQLException("Syntaxerror") because your test did not
cover all possible paths (which in practice is impossible mostly because
of the exponential growth of possible paths).
 
A

Andrea Desole

Thanks for all the replies. I tried the reflection method but it turns
out that getField() doesn't allow access to private members. Checked in
the JDK, which says:

"Returns a Field object that reflects the specified public member field
of the class or interface represented by this Class object. The name
parameter is a String specifying the simple name of the desired field."

as Thomas said, I pointed to the wrong method: use getDeclaredField
So it seems to not allow access to private members. A few others seemed
to think reflection should work, can anyone give a working example? As
I say it is a hack and I agree with the comments about the code itself
not exactly being a good design but please bear in mind I have no
control over this code or authority to change it so I don't think I
have much choice to make the test work (all the customer is bothered
about is seeing 100% statement coverage!!)

and why does it involve reinitializing a static variable? When you have
it initialized it once that code is covered, isn't it? Or am I using the
wrong definition of "statement coverage"?
Anyway, I would consider writing more tests
 
A

Andrea Desole

Patricia said:
As long as a Class is reachable, its ClassLoader is also reachable
through the Class's getClassLoader method.

this is clear
Being unreachable is a necessary, but not sufficient, condition for
garbage collection. See section 12.6.1 of the JLS for the details.

This is not clear.
To point out a paragraph in the specification would usually be enough,
but this time I still don't get it. Sorry.
Paragraph 12.6.1 is about finalizability and reachability. No mention of
garbage collection or class loading/unloading. I would really
appreciate some quoted text. Besides, it looks a bit strict to me to
keep an object that will never be used again (because its references are
lost), because its class loader is not unloaded.
 
T

Tor Iver Wilhelmsen

Andrea Desole said:
mmm, I actually think the private static member will never change as
long as the JVM runs

No, the class object can be garbage collected in some scenarios.
 
A

Andrea Desole

Andrea said:
This is not clear.
To point out a paragraph in the specification would usually be enough,
but this time I still don't get it. Sorry.
Paragraph 12.6.1 is about finalizability and reachability. No mention of
garbage collection or class loading/unloading. I would really
appreciate some quoted text. Besides, it looks a bit strict to me to
keep an object that will never be used again (because its references are
lost), because its class loader is not unloaded.

never mind. I was just misunderstanding
 
R

Roedy Green

I'm not allowed to redesign the class so I can't add
a "setter" method for this variable or make it public. So what I really
need to do is make sure that all previously use objects of this are
garbage collected...

If you can't change or extend the class in any way, You have set
yourself an impossible task.

I am pretty sure you are thinking about your problem is a way
guaranteed to create failure. Let's say I gave you a method to
determine if all old objects had been GCed. What would you do if they
had not been?

The solution to your problem may lie is using a different classloader
which effectively lets you have two flavours of the same class of
object kicking around each with their own set of statics.

This might be used in a non-stop system where you have to allow
changing code or layout for an object on the fly.
 
R

Roedy Green

Classes that mutate static members are inherently detestable. If you
have to deal with very poor code, then your choices are either
reflection with a high dependency on your tested code or playing silly
buggers with class loaders.

If you can't modify the original, you can test a modified original and
make extrapolations about what those test results mean about how the
original would behave. In other words, you can temporarily instrument
the class.
 

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,755
Messages
2,569,537
Members
45,023
Latest member
websitedesig25

Latest Threads

Top