Skip to content

Critical Memory Leak #501

Description

@Sevin777

I have been using Tern extensively for a while now in my Chrome App and occasionally it creates a memory leak that causes RAM usage to skyrocket and it maxes out the CPU at the same time, which causes the app to become completely unresponsive.

I can't figure out exactly what is causing this but I know for a fact its part of tern (or acorn) as I have now managed to reproduce it on your Tern Demo. I stripped down my code that reproduces the issue as much as possible by repeatedly removing code and testing to see if the error would still occur. However, the test code that causes the error is still somewhat large. Note: I've run into this type of error many times, this is simply the first time I've decided to dig into the cause and find code that is guaranteed to reproduce the error

Steps to reproduce:

  • I've tested in FireFox and Chrome and both reproduce the issue
  • Paste the code below into the Tern Demo
  • Go to line 103 and type the following cnt.append('testing')
    • Once you get in the function call the error will occur
  • If using chrome, open Chrome's task manager and watch the CPU/RAM for the Task
  • The comments at the top of the code are actually required to reproduce the error...
/*jshint maxerr:10000, eqnull:true */







//Used to delay resize of child frames
// var ResizeDelayer;
// //window resize event
// $(window).resize(function() {
//     df_winH = null;
//     df_winW = null; //reset window hieght/width vars

//     // log('adjust size fired from browser');
//     if (DashBoardPreviewIsOpen()) {
//         SetPreviewSize(); //prevent preview overflow
//     }
//     if (ResizeCurFullScreenFrame()) {
//         AutoSizeConfigFrame(); //need this here before qutting
//         return;
//     }
//     AdjustLayout();
//     AutoSizeConfigFrame(); //must be after AdjustLayout()
//     clearTimeout(ResizeDelayer); //do not allow child frames to resize on minor adjustments and delay it so parent page finishes processing first
//     ResizeDelayer = setTimeout(ResizeChildren, 100);
// });



var dbQF = (function() {
    var local = {},
        parentClass = null,
        mixins = [apState.prototype, microProp.prototype, microEvent.prototype];

    var Class = function() {
        var _sf = {}, sf = this;
        if (parentClass) parentClass.call(this /*, args*/ );
        (function Public() {
            /**
             * @approp @type {bool} [false] is visible
             */
            this.visible = function(v) {
                var Get = function(v) {
                    return v;
                };
                var Set = function(v, same, current, cb) {
                    if (same()) {
                        console.log('same');
                        return;
                    }
                    cb(v); //return new value

                    RightColumnQF().toggle(v);
                    AutoSize_RightColumnChildren();
                    sf.render();
                };
                return this.mp(this, 'visible', false, v, Get, Set);
            };
            /**
             * @approp @type {bool} [false] description
             */
            this.configVisible = function(v) {
                var Get = function(v) {
                    return v;
                };
                var Set = function(v, same, current, cb) {
                    //#region set value
                    if (same()) return;
                    v = _.toBool(v);
                    if(!v) return v;
                    cb(v);
                    //#endregion


                    //#region create dialog
                    var cnt = $('<div id="dbQF_config" title="Configure Date Filter"></div>');
                    cnt.dialog({
                        modal: true,
                        width: 450,
                        close: function(event, ui) {
                            sf.configVisible(false);
                            $(this).dialog('destroy').remove();
                        }
                    });
                    cnt = $('#dbQF_config');
                    //#endregion

                    var fields = {};
                    var count = LayoutContainerCount(dbCurLayout);
                    for (var i = 1; i <= count.length; i++) {
                        fields[i] = createField(i);
                    }

                    /**
                     * @returns {apField}
                     * @param {int} num - frameNumber
                     */
                    function createField(num){
                        //type the following line of code... once you get in the fn call the error will occur
                        //cnt.append('testing')

                    }
                };
                return this.mp(this, 'configVisible', false, v, Get, Set);
            };


            /**
             * @apField
             */
            this.dateType = new apField({
                name: 'dateType',
                question: 'Date Type',
                controlType: apfEN.controlType.select,
                databaseType: apfEN.databaseType.int,
                defaultValue: fbEN.dateType.relativeSimple.v,
                listOps: {
                    includeBlank: false,
                },
                listItems: function() {
                    return [{
                        t: 'Relative',
                        v: fbEN.dateType.relativeSimple.v
                    }, {
                        t: 'Static',
                        v: fbEN.dateType.Static.v
                    }];
                },
                renderOps: {
                    renderTargetByName: true,
                    renderReplace: true,
                },
                width: 'Q70,L5,A75,V0',
            });
            /**
             * @apField
             */
            this.dateSelect = new apField({
                name: 'dateSelect',
                question: 'Date Filter',
                controlType: apfEN.controlType.select,
                databaseType: apfEN.databaseType.varchar,
                defaultValue: '',
                placeholder: '(select)',
                // listOps: {
                //     includeBlank: false,
                // },
                listItems: function(cb) {
                    AP.apAjax(fbEN.constant.serverClass, fbEN.serverMethod.GetDateList, {}, function(s, err, abort) {
                        cb(s);
                    });
                },
                renderOps: {
                    renderTargetByName: true,
                    renderReplace: true,
                },
                events: [{
                    ev: apfEN.event.toggle_visible,
                    fn: function() {
                        return sf.isRelative();
                    }
                }],
                deps: [{
                    fn: function() {
                        this.toggle_visible();
                    },
                    fields: [sf.dateType]
                }],
                width: 'Q70,L5,A220,V0',
            });
            /**
             * @apField
             */
            this.dateTextbox1 = new apField({
                name: 'dateTextbox1',
                question: 'Date Filter',
                controlType: apfEN.controlType.textbox,
                databaseType: apfEN.databaseType.date,
                defaultValue: '',
                placeholder: 'eg: 1/1/2000',
                renderOps: {
                    renderTargetByName: true,
                    renderReplace: true,
                },
                events: [{
                    ev: apfEN.event.toggle_visible,
                    fn: function() {
                        return !sf.isRelative();
                    }
                }],
                deps: [{
                    fn: function() {
                        this.toggle_visible();
                    },
                    fields: [sf.dateType]
                }],
                width: 'Q70,L5,A100,V0',
            });
            /**
             * @apField
             */
            this.dateTextbox2 = new apField({
                name: 'dateTextbox2',
                question: 'To',
                controlType: apfEN.controlType.textbox,
                databaseType: apfEN.databaseType.date,
                defaultValue: '',
                placeholder: 'eg: 2/1/2000',
                renderOps: {
                    renderTargetByName: true,
                    renderReplace: true,
                },
                events: [{
                    ev: apfEN.event.toggle_visible,
                    fn: function() {
                        return !sf.isRelative();
                    }
                }],
                deps: [{
                    fn: function() {
                        this.toggle_visible();
                    },
                    fields: [sf.dateType]
                }],
                width: 'Q15,L5,A100,V0',
            });


            /**
             * @returns {bool} true if dateType is relative
             */
            this.isRelative = function() {
                return sf.dateType.value() === fbEN.dateType.relativeSimple.v;
            };

            this.render = function() {
                // var sf = this;
                if (sf.Done('render')) return;
                var c = qfMainCnt();
                sf.dateType.render();
                sf.dateSelect.render();
                sf.dateTextbox1.render();
                sf.dateTextbox2.render();


                sf.Done('render', true);
            };
        }).call(sf);
    };



    microMixin(Class.prototype, mixins, parentClass);
    return new Class();
}());

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions