12-09-2009 07:30 AM
I have a fairly advanced java question for anyone interested in minute JVM architecture details.
I recently encountered this 'strange' behavior:
The Application (extended from UiApplication) maintains it's reference by using singleton pattern but to further extend it to be a 'global singleton' the same reference is also stored in runtime storage (although that part seems to be irrelevant).
The application (among other things) registers to listen to Phone events.
Now I do some work and take a sip of tea. Then I decide to stop using the app.
Before exiting the app, I unregister the Phone event listener, clear the runtime storage and just exit(0).
Now I check and validate that the Phone listener has unregistered: check OK.
But (here comes the surprise) when I start the app again (store new instance, register the listener, etc.) and then test the Phone listener, the listener's Application instance carries the first application reference and Process ID !?
I have theorized around the subject with my colleagues and we all concluded that the listener somehow uses only one 'instance' of static members for every class it encounters.
Even if I exit and delete every possible trace of the original process/application, Phone listener (once I register to it again) always remembers the first time we met
Any comments ?
12-09-2009 07:41 AM
you call Phone.removePhoneListener before System.exit?
Where do you check for the process id? In the phone application? What happens to the reference after you call removePhoneListener?
PhoneListeners use weak references that remain after the registering process is killed, but i thought the remove method would kill the reference.
12-09-2009 07:44 AM - edited 12-09-2009 08:44 AM
"the listener's Application instance carries the first application reference and Process ID "
Isn't the listener running under the process for the Phone application, which does not change in the process you have just outlined.
Note also that because this listener is running in a different process, it will get different static variables to those you see in your application.
Edit, just to say I had not seen Simon's response when I posted this.
12-09-2009 08:13 AM - edited 12-09-2009 08:21 AM
Thank you for the reply.
1) yes. I unregister the listener
2) yes. I check it in the phone application (just put a watch variable with full static object path, and additionaly you can add a second static string which you change in the second run, but not in the first - you will notice it remains unchanged after restarting the app when looked upon from the Phonelistener, but changed in my application context. That suggests two instances of static objects, right?
3) After removing the listener, the reference get's destroyed by the exit() call (AFAIK). I cannot test it in the Phone listener until I register it again (of course) and then I see it has the old reference stored.
I also agree with you assumption about killing references after exiting the app.
But It seems that the GC doesn't collect the reference because it is a static ?
In principle everything works ok, but I cannot change the static objects anymore since any changes done will be on a 'local' static and not on the phone listener's version . Strange but true
Any ideas ?
Edit: was in edit mode when Peter posted
12-09-2009 08:20 AM - edited 12-09-2009 08:24 AM
Exactly what we concluded.
But doesn't it seem strange bahaviour?
You instantinate A, it has static member B.
The first time A register's as Phone listener you can edit B as much as you want.
Once you unregister + exit() you will never have access to the original B, since the second time you register as Phone listener it will reuse static given in the first run but you will use a new B' instance
Now combine this with a singleton pattern and you get a 'demon' object 'running live' even after you killed it.
How's that for a hack
12-09-2009 08:29 AM
If it is not observable it doesn't matter and will get GC;ed evnetually- if it matters, someone can see it.
I would use persistent objects since I'm more familiar with those but you ought to
be able to set your own variables to track create/destroy times or counts and you can
popup a global screen to check your results. So, if your app increments a persistent variable
each create or destroy, your listener should be able to see that change. Generally statics
create problems anyway- static collections become junk bins that eventually exhaust memory
with stale ( strong ) references unless care is taken.
You see some similar issues with applets and j2se but really to get a different set of statics means you
have a different class- internally the jvm has to tack on a process ID to a class ID when it lloads a class.
Getting a different set of statics for use with a given object depending on the calling process would
be quite confusing. Maybe just generally it is best to avoid statics in this setting.
12-09-2009 10:08 AM
myraddin, can you post some demo code?
12-10-2009 05:47 AM - edited 12-10-2009 05:47 AM
Thank you all for your input.
I agree with your thoughts and conclusion. AFAIK, there is a topic about multiple JVM's being started.. but I just cannot find the link anymore. The idea (explained) was that each app can have multiple processes, each process can have set of loaders, each loader has multiple JVM and each jvm has its own static instances. (I probably misused a few relations up there)
In short, I am trying to avoid using singletons from now on (at least for anything related to listeners)
It's a bit hard to extract the necessary code bits right now, but you can reproduce it by following the instructions in previous posts, but I will sure try to find some time to get the code on this thread, sorry for this.
12-10-2009 05:55 AM
singletons are fine, just put them into the runtimestore instead of relying on the static context.