Max, clearly these all need to be addressed, either before you check in or in
an amendment to your checkin.
Thank you as usual André for a most thorough review!
On 2010-03-29, at 16:45, André Bargull wrote:
> Did anybody said comments are no longer allowed to delay the checkin? :-P
>
> LzTextSprite (swf8):
>> + if (! this['scrolldel']) {
>> + this.scrolldel = new LzDelegate(this, "__LZupdateScrollAttrs");
>> + }
> and later:
>> + if (this.scrolldel.hasevents) {
>> + this.scrolldel.destroy();
>> + }
> I'm asking myself why you've used the "save" property access (bracket syntax)
> when no harm can occur, but later the "brute force" method (scrolldel could
> be undefined)? I'd just remove the bracket syntax and use direct property
> access.
>
>
> LzXMLLoader
>> + // To keep delegates from resurrecting us. See LzDelegate#execute
>> + this.__LZdeleted = true;
> LzXMLLoader is a LzLoader, which is a LzEventable, so you must not set
> _LZdeleted.
>
> LzDelegate
>> - } else {
>> - keep.push( ev );
>> + this.__events.splice(i, 1);
>> + break;
>> }
> You cannot use 'break' here, a delegate can be registered to an event more
> than once.
>
> LzHTTPDataProvider
>> + /**
>> + * @access private
>> + * @param LzHTTPDataRequest dreq:
>> + * @param LzDataElement data:
>> + */
>> + override function destroy() {
> Wrong comment..
>
> LzDataset
>> override function destroy () {
>> this.$lzc$set_childNodes([ ]);
>> + this.dataprovider.destroy();
> You must not destroy the dataprovider, dataproviders are singleton objects!
> For example the default dataprovider for a dataset is
> canvas.defaultdataprovider, so all datasets share the same dataprovider!
>
>
>
>
>
> On 3/29/2010 8:05 PM, P T Withington wrote:
>> Approved.
>>
>> Let's check this in so we can get some QA on it (and before someone thinks
>> up another amendment to delay the vote).
>>
>> Nice work on a thorny problem!
>>
>> On 2010-03-24, at 17:45, Max Carlson wrote:
>>
>>
>>> Change 20100314-maxcarlson-0 by maxcarl...@bank on 2010-03-14 00:54:51 PST
>>> in /Users/maxcarlson/openlaszlo/trunk-clean
>>> for http://svn.openlaszlo.org/openlaszlo/trunk
>>>
>>> Summary: UPDATE 6: Automatically remove invalid delegates in
>>> LzEventable.destroy()
>>>
>>> Bugs Fixed: LPP-8822 - Improve layout performance
>>>
>>> Technical Reviewer: ptw
>>> QA Reviewer: hminsky
>>>
>>> Release Notes: It is no longer necessary to manually track and release
>>> delegates whose target is 'this' to prevent memory leaks. This is handled
>>> automatically by the event system.
>>>
>>> Details: Updated to address Tucker's comments:
>>> General comment:
>>>
>>> It really sucks that LzDataAttrBind pretends to be an LzDelegate but isn't
>>> really. We probably should use interface/implements to make that more
>>> explicit. At least then the swf10 back-end could give us some help.
>>>
>>> Nits:
>>>
>>> 1) LzEventable#105 Not sure what this means:
>>>
>>>
>>>>> // uncomment to LFC delegates cleaned up, e.g. datapath and inputtext
>>>>> //if ($debug) Debug.warn('removing %w delegates from %w.',
>>>>> this.__delegates.length, this);
>>>>>
>>> I removed this.
>>>
>>> 2) LzNode#400:
>>>
>>> /** Tracks constraint delegates
>>> @access private */
>>>
>>> Might be better to say:
>>>
>>> /** Tracks delegates and data bindings for states so they can be
>>> applied/removed
>>>
>>> because that is what we have reduced this to. Perhaps someday we can come
>>> up with a less kludgey mechanism than state reaching out and grabbing these
>>> things from the node constructor.
>>>
>>> Done.
>>>
>>> Issues:
>>>
>>> 1) LZNode#2080
>>>
>>>>> //remove __LZconstraintdelegates
>>>>> // We have to do this to remove LzDataAttrBinds
>>>>>
>>> I don't follow. It seems to me that in LzNode/dataBindAttribute, the
>>> LzDataAttrBind object needs to go on __LZconstraintDelegates, so it can be
>>> applied/unapplied by LzState. But LzDataAttrBind's constructor should
>>> register the binding on __delegates so that it can be auto-cleaned when the
>>> node it is binding is destroyed. We really want to separate these two
>>> tasks so future generations don't have to work this out again. Then you
>>> can truly just let __LZconstraintdelegates drop on the floor in
>>> LzNode/destroy.
>>>
>>> Yeah, you're right! Done.
>>>
>>> 2) LzDataAttrBind/unregisterAll: Does anyone actually call this any more?
>>> LzEventable/destroy should just be calling LzDataAttrBind/destroy
>>>
>>> Removed unregisterAll().
>>>
>>> 3) LaszloEvents#227: There needs to be a comment here. Something like
>>> "Delegates between LzEventables can cause memory leaks. We record such
>>> delegates so they can be cleaned up in destroy".
>>>
>>> Done.
>>>
>>> 4) LaszloEvents#227: Do you not have to test that the context _is_
>>> actually an LzEventable here? At least in the runtimes that don't enforce
>>> types?
>>>
>>> Ooh good point! I improved the testing and ensured LzDelegate.__tracked is
>>> correctly maintained.
>>>
>>> 5) LaszloView#1795: Why did you un-deprecate releaseLayouts? I thought we
>>> were trying to get rid of this?
>>>
>>> I removed it since it's deprecated in 4.7.1 - but there doesn't seem to be
>>> a replacement. It could be useful when you want to move things around
>>> without layouts interfering - but you could lock/unlock the layouts
>>> instead. Maybe we should make the layouts array public so folks could do
>>> this? The replication manager does this during updates...
>>>
>>> Otherwise, the same as r5 (Updated to address Andre's comments):
>>> LzDelegate:
>>>
>>>> + if (eventSender !== this.c) {
>>>> + var _dels:Array = this.c['__delegates'];
>>>> + if (_dels == null) {
>>>> + this.c.__delegates = [ this ];
>>>> + } else {
>>>> + _dels.push( this );
>>>> + }
>>>> + }
>>>>
>>> 1) This will create multiple entries for each delegate, you should add a
>>> boolean flag to track whether the delegate was already added to the
>>> __delegates array to prevent more than one entry.
>>>
>>> Done.
>>>
>>> 2) What about the issue with the swf8 kernel using LzDelegates?
>>>
>>> I updated the swf8 kernel to be very careful about unregistering all
>>> delegates used on instances.
>>>
>>>
>>> LzDelegate:
>>>
>>>> +public function destroy ():void {
>>>> + this.unregisterAll();
>>>> + this.c = null;
>>>> + this.m = null;
>>>> +}
>>>>
>>> Please add "@access private" to hide the function from the docs - can you
>>> remind me why functions are added to the docs by default?! There is a JIRA
>>> issue to switch this default behaviour, isn't it?
>>>
>>> Done. I think it's that way to force developers to notice that they need
>>> to write documentation...
>>>
>>> LzNode:
>>>
>>>> + for ( var i = dels.length - 1; i>= 0; i-- ){
>>>> + if (dels[i].c) {
>>>> + dels[ i ].destroy();
>>>> + }
>>>> }
>>>>
>>> Won't work for LzDataAttrBind - there is no "c" attribute, so the if-test
>>> will fail.
>>>
>>> Done. I added a __LZdeleted flag to LzDelegate that can be used instead.
>>>
>>> LaszloEvents - Add __events array to track events registered on the
>>> delegate and make LzDelegate static. Add hasevents boolean to track
>>> whether calls to unregisterAll() are needed. Add __tracked flag to prevent
>>> adding to __delegates more than once. Add __LZdeleted flag to track when
>>> to destroy(), mirroring LzEventable.
>>>
>>> LzHTTPDataProvider - Track LzHTTPLoaders and call destroy() on each one
>>> when destroyed.
>>>
>>> LzDataset - Call destroy() on the dataprovider when destroyed.
>>>
>>> kernel/*/LzHTTPLoader - Add destroy() method which is called when a loader
>>> should be destroyed. Add stub methods for swf9 and dhtml.
>>>
>>> LzState, LzNode - Use LzDelegate/LzDataAttrBind.__LZdeleted to decide
>>> whether to call destroy().
>>>
>>> kernel/swf/* - Ensure all delegates not used by global services are tracked
>>> and destroyed. Use new hasevents flag to avoid unneeded calls to
>>> unregisterAll().
>>>
>>> Otherwise, the same:
>>>
>>> LzNode,LzState - Rename __LZdelegates -> __LZconstraintdelegates, shorten
>>> array lookups where possible, use LzDelegate.destroy() instead of
>>> unregisterAll().
>>>
>>> LaszloEvents - Add check/warning when a delegate is created for an invalid
>>> context. Move __delegates tracking to register() and only add LzEventables
>>> that are registering for a different context. Add warnings for unneeded
>>> unregisterAll() calls, but comment them out due to too many warnings. Add
>>> destroy() API that neuters and unregisters the delegate.
>>>
>>> LzDataAttrBind - Add destroy() API for symmetry with LzDelegate.
>>>
>>> LzDatapath - Use super.destroy() for efficiency.
>>>
>>> LaszloView - releaseLayouts() now calls layout.destroy().
>>>
>>> LzState - Rename __LZstatedelegates -> __LZstateconstraintdelegates.
>>>
>>> Otherwise, the same as before:
>>>
>>> LzInputText,LzAnimatorGroup,LzDatapointer,LzDataset - Remove extra delegate
>>> unregistration as it's now handled by the event system.
>>>
>>> LzEventable - Add _delegates array to hold delegates that have a context
>>> pointing to this object. Clean out delegate contexts in destroy().
>>>
>>> LaszloEvents - LzDelegate registers on its contexts' _delegates array.
>>>
>>> LaszloLayout,resizelayout - don't track delegates anymore.
>>>
>>>
>>> Tests: Run modified leak-components test in swf10 - the memory monitor in
>>> the upper left shows much less leakage with this patch: you can click the
>>> monitor to force garbage collection. Also run smokecheck across runtimes.
>>>
>>> Files:
>>> M test/components/lz/leak-components.lzx
>>> M WEB-INF/lps/lfc/kernel/swf/LzTextSprite.as
>>> M WEB-INF/lps/lfc/kernel/swf/LzMediaLoader.lzs
>>> M WEB-INF/lps/lfc/kernel/swf/LzInputTextSprite.as
>>> M WEB-INF/lps/lfc/kernel/swf/LzXMLLoader.lzs
>>> M WEB-INF/lps/lfc/kernel/swf/LzMakeLoadSprite.as
>>> M WEB-INF/lps/lfc/kernel/swf/LzHTTPLoader.as
>>> M WEB-INF/lps/lfc/kernel/swf/LzSprite.as
>>> M WEB-INF/lps/lfc/kernel/dhtml/LzHTTPLoader.js
>>> M WEB-INF/lps/lfc/kernel/swf9/LzHTTPLoader.as
>>> M WEB-INF/lps/lfc/core/LzNode.lzs
>>> M WEB-INF/lps/lfc/core/LzEventable.lzs
>>> M WEB-INF/lps/lfc/views/LzInputText.lzs
>>> M WEB-INF/lps/lfc/views/LaszloView.lzs
>>> M WEB-INF/lps/lfc/helpers/LzState.lzs
>>> M WEB-INF/lps/lfc/events/LaszloEvents.lzs
>>> M WEB-INF/lps/lfc/controllers/LzAnimatorGroup.lzs
>>> M WEB-INF/lps/lfc/controllers/LaszloLayout.lzs
>>> M WEB-INF/lps/lfc/data/LzDatapointer.lzs
>>> M WEB-INF/lps/lfc/data/LzHTTPDataProvider.lzs
>>> M WEB-INF/lps/lfc/data/LzDataset.lzs
>>> M WEB-INF/lps/lfc/data/LzDatapath.lzs
>>> M WEB-INF/lps/lfc/data/LzDataAttrBind.lzs
>>> M docs/src/developers/delegates.dbk
>>> M lps/components/rpc/ajax.lzx
>>> M lps/components/extensions/html.lzx
>>> M lps/components/utils/layouts/resizelayout.lzx
>>> M lps/components/utils/replicator/replicator.lzx
>>> M lps/components/av/rtmpstatus.lzx
>>> M lps/components/base/basetabelement.lzx
>>> M lps/components/base/basescrollbar.lzx
>>> M lps/components/base/basecomponent.lzx
>>> M lps/components/base/basewindow.lzx
>>> M lps/components/base/submit.lzx
>>> M lps/components/base/basetrackgroup.lzx
>>> M lps/components/base/basedatacombobox.lzx
>>>
>>> Changeset:
>>> http://svn.openlaszlo.org/openlaszlo/patches/20100314-maxcarlson-0.tar
>>>
>>>
>>
>>
>>