(Stephen, please read this mail... bad news regarding proxy-es.)
Sunday, December 14, 2003, 5:56:53 PM, Niclas Hedhman wrote:
> On Monday 15 December 2003 00:32, Daniel Dekany wrote:
>> Sunday, December 14, 2003, 2:28:14 PM, Stephen McConnell wrote:
>> > The soft reference is to the proxy so if the reference returns null we
>> > know that the proxy has been finalized which means that the
>> > corresponding component has been decommissioned.
>>
>> [snip]
>>
>> Why? Is it a soft reference cleared exactly when the referenced object
>> is finalized? Is this two act united to form an atomic operation? I
>> think they are not, so it is possible that the soft ref. cleared earlier
>> than finalization is called (but please point out if the JVM spec.
>> states something that prevents this to happen), so it is till not
>> ensured that finalize() will be called before the VM terminates.
>
> Stephen,
> I agree with Daniel's sentiment, that it is dangerous to play around with
> these matters by "observation of behaviour". Everything needs to be
> strictly(!) checked with the JLS, otherwise we are in for extremely subtle
> and intermittent problems in the future.
>
> So looking at the state diagram, what is actually happening;
>
> Proxy goes;
> A - B - G - K - F
>
> Component goes;
> A - B - G
> then it may either go
> K
> or
> M - J
> or
> M - C - K
> and finally it may go
> F
> or
> D - N - F
>
> It can NEVER go (read the text)
> A - E
>
> Isn't that so?
>
> End of the Day, Stephen has a point, the component will never become
> unreachable before the finalize() method in the Proxy !
> Why?
> Because, if the finalizer have proceeded to reachable/finalized before the
> Proxy does the G transition, the component will make a D transition, and when
> the Proxy is making the K transition , the component will N and the F.
>
>
> Q.E.D.
> Stephen is right!!! (Although using the wrong method to be right.)
[snip]
Sorry, I don't get it... Does the -- obviously correct -- statement "the
component will never become unreachable before the finalize() method in
the Proxy" prove what? I belive it does *not* prove that:
a)
The soft ref. to the proxy can't be cleared earlier that its
finalize() method is executed.
The docs of lang.ref doesn't talk about
reachable/f-reachable/unreachable: "An object is strongly reachable if
it can be reached by some thread without traversing any reference
objects. A newly-created object is strongly reachable by the thread that
created it. An object is softly reachable if it is not *strongly
reachable* but can be reached by traversing a soft reference." Again, if
it is not "strongly reachable", and not if "not reachable". One may
argue, that "can be reached by some thread without traversing any
reference objects" stand only when the object is already entered of left
the last stage (unerachable/finalized). But I'm pretty sure it's not the
case, since I know from experiment that Sun JVM used to clear weak
references approximately at the moment of finalize() invocation (it's
not measurable if it is before that or just after that), and does not
wait until finalize() returns, so it cleanly does not wait for state
change "F". And, soft refs are cleared before weak refs.
b) The component can't enter "finalized" state before the proxy enters
"finalized". Anyway, it is just proved to be false empirically:
I have made an experiment regarding b). It cleanly shows that the
component is possibly finalized before the proxy, on the JVM comes with
Sun's J2SE 1.4.2 for Windows.
<code file="Test.java">
import java.lang.ref.*;
public class Test {
public static void main(String[] args) throws Throwable {
A c = new A("component", null);
A p = new A("proxy", c);
c = null;
p = null;
for (int i = 0; i < 10000; i++) {
System.gc();
Thread.sleep(100);
}
}
}
class A {
private final String m_id;
private final A m_refed;
int[] m_eatMemory = new int[1024*256];
public A(String id, A refed) {
m_id = id;
m_refed = refed;
}
public void finalize() throws Throwable {
p("finalize() started for " + m_id
+ " (stores ref to: "
+ (m_refed != null ? m_refed.m_id : "null") + ")");
Thread.sleep(1000);
p("finalize() ended for " + m_id);
}
public static void p(Object o) {
synchronized(System.out) {
System.out.println(o.toString());
System.out.flush(); // You never know... :)
}
}
}
</code>
When I run this, I get:
finalize() started for component (stores ref to: null)
finalize() ended for component
finalize() started for proxy (stores ref to: component)
finalize() ended for proxy
Ops! And, when I replace the first 4 line of main(...) with this:
A p = new A("proxy", new A("component", null));
p = null;
then I get:
finalize() started for proxy (stores ref to: component)
finalize() ended for proxy
finalize() started for component (stores ref to: null)
finalize() ended for component
So it seems the it is rather creation order that has influenced the
order if finalize() calls, and not the structure of the reference graph.
--
Best regards,
Daniel Dekany
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]