out-of-date CompiledMethod

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

out-of-date CompiledMethod

Nicolas Cellier
Hi,
Some CompiledMethod might be replaced in their respective MethodDictionary (recompiled), but persist in the system when they have some block referenced.

We can track them down with this snippet:

     (CompiledMethod allInstances reject: #isInstalled) inspect.

Most of the time, it's innocuous, but if the method were recompiled due to a change of class layout and if the block access inst. var. slots that since moved, all sort of undefined behavior can happen, including a VM crash.

I thought I could track such case down with this snippet:

    (CompiledBlock allInstances reject: [:e | e isClean or: [each home method isInstalled]]) inspect.

or:

    (BlockContext allInstances reject: [:e | e closure isClean or: [each home method isInstalled]]) inspect.

But both BlockContext and CompiledBlock allInstances isEmpty. Ah yes, CompiledBlock is future for Sista, and now we only get Context in Spur...

    (Context allSubInstances reject: [:e | e methods isInstalled]) inspect.

gives a longer list than the first snippet, because the out-of-date method might be used in many different context...

However, I can't find those having dangerous (not clean) blocks:

    (Context allSubInstances reject: [:e | e closure isNil]) inspect.
    (Context allSubInstances reject: [:e | e closure isNil or: [e closure isClean]]) inspect.
    (Context allSubInstances reject: [:e | e closure isNil or: [e closure isClean or: [e method isInstalled]]]) inspect.

The first two lists are not empty, but the last one is empty. So that's still  not the right invocation: there is no active Context for those closure, so here is a better snippet:

    (BlockClosure allSubInstances reject: [:e | e outerContext method isInstalled or: [e isClean]]) inspect.

In a VMMaker image built from latest squeak distribution, the out-of-date CompiledMethods given by the first snippet is below:

(WorldMenuProvider>>#preferencesBrowser "a CompiledMethod(3800333)") .
(WorldMenuProvider>>#nextWindow "a CompiledMethod(1345923)") .
(WorldMenuProvider>>#closeTopWindow "a CompiledMethod(1052691)") .
(WorldMenuProvider>>#helpOnServices "a CompiledMethod(1013869)") .
(WorldMenuProvider>>#rebuildRegistry "a CompiledMethod(2839737)") .
(WorldMenuProvider>>#servicesBrowser "a CompiledMethod(485047)") .
(WorldMenuProvider>>#createNewService "a CompiledMethod(2658559)") .
(WorldState>>#stepListSortBlock "a CompiledMethod(491105)") .
(ServiceAction class>>#id:text:button:description:action: "a CompiledMethod(3812069)") .
(ServiceAction class>>#text:button:description:action: "a CompiledMethod(1460587)") .
(ServiceCategory class>>#text:button:description: "a CompiledMethod(3025003)") .
(ServiceShortcuts class>>#insertPrefShortcut: "a CompiledMethod(2077141)") .
(WeakRegistry>>#installFinalizer "a CompiledMethod(1322897)") .
(PluggableDictionary class>>#integerDictionary "a CompiledMethod(353359)") .
(Slider>>#computeSlider "a CompiledMethod(682213)") .
(MorphicAlarmQueue>>#migrate "a CompiledMethod(1994485)") .
(SqueakReleaseNotes class>>#asHelpTopic "a CompiledMethod(79489)") .
(SqueakTheme class>>#addToolColors: "a CompiledMethod(1225541)") .

+ a bunch of DoIt's for which I can't find the pointers (referenced by nothing, can it be a memory leak from VM?).

By using 'chase pointers' menu, or the second snippet to catch Context, most come from ServiceRegistry.
There are also special sortBlock for Heap (stepListSortBlock from WorldState>>initialize and also WorldState alarms) or hashBlock (integerDictionary from Unicode ToUpper).
The HostWindowProxy registry has the obsolete installFinalizer.

And the unclean closure given by latest snippet are very few (copy omitted):

[closure] in WorldMenuProvider>>helpOnServices
[closure] in ServiceShortcuts class>>insertPrefShortcut:
[closure] in WeakRegistry>>installFinalizer
[closure] in MorphicAlarmQueue>>migrate

Most are not clean because they close over self or a method argument.
The only potentially problematic is the one closing over an inst. var. (more over for writing!) WeakRegistry>>installFinalizer.
It would be safer to transform this closure to just send a message rather than messing directly with the ivar...

It's not a problem right now until we change WeakRegistry layout, but I wanted to share these findings, since that's the kind of tricky things we must care of when releasing a new version.





Reply | Threaded
Open this post in threaded view
|

Re: out-of-date CompiledMethod

marcel.taeumel
Hi Nicolas,

thank you for this information. Looks like we need more #cleanUp: methods in this regard. For our timer interrupt watcher, I did already add that to the Delay class.

That is, we have to look for the correct classes to clean up, which should then free the CompiledMethod instances automatically.

Best,
Marcel

Am 30.08.2019 18:05:10 schrieb Nicolas Cellier <[hidden email]>:

Hi,
Some CompiledMethod might be replaced in their respective MethodDictionary (recompiled), but persist in the system when they have some block referenced.

We can track them down with this snippet:

     (CompiledMethod allInstances reject: #isInstalled) inspect.

Most of the time, it's innocuous, but if the method were recompiled due to a change of class layout and if the block access inst. var. slots that since moved, all sort of undefined behavior can happen, including a VM crash.

I thought I could track such case down with this snippet:

    (CompiledBlock allInstances reject: [:e | e isClean or: [each home method isInstalled]]) inspect.

or:

    (BlockContext allInstances reject: [:e | e closure isClean or: [each home method isInstalled]]) inspect.

But both BlockContext and CompiledBlock allInstances isEmpty. Ah yes, CompiledBlock is future for Sista, and now we only get Context in Spur...

    (Context allSubInstances reject: [:e | e methods isInstalled]) inspect.

gives a longer list than the first snippet, because the out-of-date method might be used in many different context...

However, I can't find those having dangerous (not clean) blocks:

    (Context allSubInstances reject: [:e | e closure isNil]) inspect.
    (Context allSubInstances reject: [:e | e closure isNil or: [e closure isClean]]) inspect.
    (Context allSubInstances reject: [:e | e closure isNil or: [e closure isClean or: [e method isInstalled]]]) inspect.

The first two lists are not empty, but the last one is empty. So that's still  not the right invocation: there is no active Context for those closure, so here is a better snippet:

    (BlockClosure allSubInstances reject: [:e | e outerContext method isInstalled or: [e isClean]]) inspect.

In a VMMaker image built from latest squeak distribution, the out-of-date CompiledMethods given by the first snippet is below:

(WorldMenuProvider>>#preferencesBrowser "a CompiledMethod(3800333)") .
(WorldMenuProvider>>#nextWindow "a CompiledMethod(1345923)") .
(WorldMenuProvider>>#closeTopWindow "a CompiledMethod(1052691)") .
(WorldMenuProvider>>#helpOnServices "a CompiledMethod(1013869)") .
(WorldMenuProvider>>#rebuildRegistry "a CompiledMethod(2839737)") .
(WorldMenuProvider>>#servicesBrowser "a CompiledMethod(485047)") .
(WorldMenuProvider>>#createNewService "a CompiledMethod(2658559)") .
(WorldState>>#stepListSortBlock "a CompiledMethod(491105)") .
(ServiceAction class>>#id:text:button:description:action: "a CompiledMethod(3812069)") .
(ServiceAction class>>#text:button:description:action: "a CompiledMethod(1460587)") .
(ServiceCategory class>>#text:button:description: "a CompiledMethod(3025003)") .
(ServiceShortcuts class>>#insertPrefShortcut: "a CompiledMethod(2077141)") .
(WeakRegistry>>#installFinalizer "a CompiledMethod(1322897)") .
(PluggableDictionary class>>#integerDictionary "a CompiledMethod(353359)") .
(Slider>>#computeSlider "a CompiledMethod(682213)") .
(MorphicAlarmQueue>>#migrate "a CompiledMethod(1994485)") .
(SqueakReleaseNotes class>>#asHelpTopic "a CompiledMethod(79489)") .
(SqueakTheme class>>#addToolColors: "a CompiledMethod(1225541)") .

+ a bunch of DoIt's for which I can't find the pointers (referenced by nothing, can it be a memory leak from VM?).

By using 'chase pointers' menu, or the second snippet to catch Context, most come from ServiceRegistry.
There are also special sortBlock for Heap (stepListSortBlock from WorldState>>initialize and also WorldState alarms) or hashBlock (integerDictionary from Unicode ToUpper).
The HostWindowProxy registry has the obsolete installFinalizer.

And the unclean closure given by latest snippet are very few (copy omitted):

[closure] in WorldMenuProvider>>helpOnServices
[closure] in ServiceShortcuts class>>insertPrefShortcut:
[closure] in WeakRegistry>>installFinalizer
[closure] in MorphicAlarmQueue>>migrate

Most are not clean because they close over self or a method argument.
The only potentially problematic is the one closing over an inst. var. (more over for writing!) WeakRegistry>>installFinalizer.
It would be safer to transform this closure to just send a message rather than messing directly with the ivar...

It's not a problem right now until we change WeakRegistry layout, but I wanted to share these findings, since that's the kind of tricky things we must care of when releasing a new version.