Hashmap Empties With No Evident Cause
Solution 1:
OK, so the problem definitely associated with Garbage Collection; but, as it turns out, the cause is a subtle code design flaw.
I was able to capture the event in the log:
11-2216:38:00.9228719-8807/? I/FIRST﹕ Doing OpState 'Turn1'11-2216:38:00.9328719-8807/? I/FIRST﹕ Doing OpState 'Turn1'11-2216:38:00.9428719-8807/? I/FIRST﹕ Doing OpState 'Turn1'11-2216:38:00.9428719-8807/? I/FIRST﹕ Doing OpState 'Turn1'11-2216:38:00.9428719-8723/? D/dalvikvm﹕ GC_CONCURRENT freed 1923K, 66%free3827K/11088K, paused 3ms+3ms, total 36ms
11-2216:38:00.9428719-8728/? I/FIRST﹕ Removed 'Delay3'from StateMap
11-2216:38:00.9428719-8728/? I/FIRST﹕ Removed OpState 'Delay3'11-2216:38:00.9428719-8728/? I/FIRST﹕ Removed 'Flash3'from StateMap
11-2216:38:00.9428719-8728/? I/FIRST﹕ Removed OpState 'Forward'11-2216:38:00.9428719-8728/? I/FIRST﹕ Removed 'Delay1'from StateMap
11-2216:38:00.9428719-8728/? I/FIRST﹕ Removed OpState 'Delay'11-2216:38:00.9428719-8728/? I/FIRST﹕ Removed 'Flash2'from StateMap
11-2216:38:00.9428719-8728/? I/FIRST﹕ Removed OpState 'Turn1'11-2216:38:00.9428719-8728/? I/FIRST﹕ Removed 'Delay2'from StateMap
11-2216:38:00.9428719-8728/? I/FIRST﹕ Removed OpState 'Delay2'11-2216:38:00.9428719-8728/? I/FIRST﹕ Removed 'Flash1'from StateMap
11-2216:38:00.9428719-8728/? I/FIRST﹕ Removed OpState 'Forward2'11-2216:38:00.9428719-8807/? I/FIRST﹕ Doing OpState 'Turn1'11-2216:38:00.9428719-8807/? I/FIRST﹕ Doing OpState 'Turn1'11-2216:38:00.9528719-8807/? I/FIRST﹕ Doing OpState 'Turn1'11-2216:38:00.9528719-8807/? I/FIRST﹕ Doing OpState 'Turn1'11-2216:38:00.9628719-8807/? I/FIRST﹕ Could not find OpState'Delay2'11-2216:38:00.9628719-8807/? I/FIRST﹕ StateMap has 0 members
11-2216:38:00.9628719-8807/? I/FIRST﹕ Exiting OpState 'Turn1'11-2216:38:00.9628719-8807/? I/FIRST﹕ No OpState to Do
11-2216:38:00.9628719-8807/? I/FIRST﹕ No OpState to Do
The 'removed' messages are from the OpState.finalize(). One additional mystery exposed by this dump is how OpState Turn1 can continue to run if it has been collected. This and an excellent Memory Leak video by Patrick Dubroy lead me to what is causing the problem.
First some context. This code is runs as an OpMode in within the FTC Robotics Control Program Main App. It is the code the student writes to control the robot. You can have as many OpModes as you like and can choose between them.
What I believe is happening is the Main App is constructing a new copy my OpMode then (what I will call Original and Copy) then running the Copy. This may happen when the OpMode is Stopped and Restarted so that the new Start on a clean copy. This causes the OpStates for Copy to get added to the static StateList. Since they have the same name, they will push the Original OpModes out of the StateList and they will be available for GC. Then, when the get collected and the finalize gets called on the Original OpStates, it will cause the Copy OpStates to get removed from the StateList because they have the same name as the Original. This also explains how an OpState can continue to run as the one that are being collected are not the active ones.
So, the solution is easy. First, I remove the overloaded finalize() and let Java manage that. Second, rather than constructing the OpStates as members, I clear the StateList and construct the OpStates in the OpMode Start() method. Since I am pretty sure the Main App won't copy the OpMode while it is running, the list should stay intact and safe.
Post a Comment for "Hashmap Empties With No Evident Cause"