1

Morning all,

I use HTAs at my company as they are quick, dirty, and easy to understand for anyone else needing to make tweaks when required (and I prefer NP++ to any other code environment I've used thus far, but no compiler).

I've made a HTA (based on IE9 but tested in IE11 also as they are comapny standard) to display some internal data to another department, this data will be updated sporadically throughout the day as and when required. This data is created in a local text file and imported using ActiveXObject XMLHttp or XMLHttpRequest where available. The issue is that when the table is updated, it leaks a little bit of memory each time.

I originally thought it was the XML request that was leaking, but I've pinned it down to when the table is actually updated.

Code is as follows:

// Create the object arrays
var vData={}, vObject={}, vMethod={}, vEvent={};

// Function to update the table
vMethod.updateTable = function() {
    vData.fileName = 'out_comm/Data.txt';
    vData.fileText = '';
    try {
        vObject.rawFile = new XMLHttpRequest();
        vObject.rawFile.open('GET', vData.fileName, false);
        vObject.rawFile.onreadystatechange = function() {
            if (vObject.rawFile.readyState === 4) {
                if (vObject.rawFile.status === 200 || vObject.rawFile.status === 0) {
                    vData.fileText = vObject.rawFile.responseText;
                }
            }
        };
        vObject.rawFile.send();
    } catch (e) {
        try {
            vObject.rawFile = new ActiveXObject('Microsoft.XMLHTTP');
            vObject.rawFile.open('GET', vData.fileName, false);
            vObject.rawFile.onreadystatechange = function() {
                if (vObject.rawFile.readyState === 4) {
                    if (vObject.rawFile.status === 200 || vObject.rawFile.status === 0) {
                        vData.fileText = vObject.rawFile.responseText;
                    }
                }
            };
            vObject.rawFile.send();
        } catch (e) {
            alert('Error: ' + e.getMessage());
        }
    }
    delete vObject.rawFile;
    vData.tableHTML = '';
    vData.BlockCount = 0;
    vData.BlockNum = 1;
    vData.BlockLetter = 'A';
    vData.rowEven = true;
    vData.fileTextSplit = vData.fileText.split('\n');
    vData.tableHTML = '<table id="dataTable" cellspacing="0"><thead><tr><th></th><th></th><th></th><th></th>';
    vData.tableHTML = vData.tableHTML + '<th>5</th><th>4</th><th>3</th><th>2</th><th>1</th>';
    vData.tableHTML = vData.tableHTML + '<th>5</th><th>4</th><th>3</th><th>2</th><th>1</th>';
    vData.tableHTML = vData.tableHTML + '<th>5</th><th>4</th><th>3</th><th>2</th><th>1</th>';
    vData.tableHTML = vData.tableHTML + '<th>5</th><th>4</th><th>3</th><th>2</th><th>1</th>';
    vData.tableHTML = vData.tableHTML + '</tr></thead><tbody>';
    for (vData.arrayCount = 0;vData.arrayCount < vData.fileTextSplit.length; vData.arrayCount++) {
        if (vData.fileTextSplit[vData.arrayCount] !== '') {
            vData.fileTextLineSplit = vData.fileTextSplit[vData.arrayCount].split(',');
            if (vData.BlockCount == 4) {
                vData.BlockCount = 0;
                if (vData.rowEven) {
                    vData.rowEven = false;
                } else {
                    vData.rowEven = true;
                }
            }
            if (vData.rowEven) {
                vData.tableHTML = vData.tableHTML + '<tr id="item_' + vData.arrayCount + '" class="even">';
            } else {
                vData.tableHTML = vData.tableHTML + '<tr id="item_' + vData.arrayCount + '">';
            }
            vData.BlockCount ++;
            vData.tableHTML = vData.tableHTML + '<td>' + vData.fileTextLineSplit[0].substring(6, 8) + '/' + vData.fileTextLineSplit[0].substring(4, 6) + '</td>';
            vData.tableHTML = vData.tableHTML + '<td>1A</td>';
            vData.tableHTML = vData.tableHTML + '<td>01</td>';
            vData.tableHTML = vData.tableHTML + '<td>' + vData.fileTextLineSplit[1] + '</td>';
            vData.tableHTML = vData.tableHTML + '<td class="split">' + vData.fileTextLineSplit[2] + '</td>';
            vData.tableHTML = vData.tableHTML + '<td>' + vData.fileTextLineSplit[3] + '</td>';
            vData.tableHTML = vData.tableHTML + '<td>' + vData.fileTextLineSplit[4] + '</td>';
            vData.tableHTML = vData.tableHTML + '<td>' + vData.fileTextLineSplit[5] + '</td>';
            vData.tableHTML = vData.tableHTML + '<td>' + vData.fileTextLineSplit[6] + '</td>';
            vData.tableHTML = vData.tableHTML + '<td>' + vData.fileTextLineSplit[7] + '</td>';
            vData.tableHTML = vData.tableHTML + '<td>' + vData.fileTextLineSplit[8] + '</td>';
            vData.tableHTML = vData.tableHTML + '<td>' + vData.fileTextLineSplit[9] + '</td>';
            vData.tableHTML = vData.tableHTML + '<td>' + vData.fileTextLineSplit[10] + '</td>';
            vData.tableHTML = vData.tableHTML + '<td>' + vData.fileTextLineSplit[11] + '</td>';
            vData.tableHTML = vData.tableHTML + '<td class="split">&pound;0</td>';
            vData.tableHTML = vData.tableHTML + '<td>&pound;0</td>';
            vData.tableHTML = vData.tableHTML + '<td>&pound;0</td>';
            vData.tableHTML = vData.tableHTML + '<td>&pound;0</td>';
            vData.tableHTML = vData.tableHTML + '<td>&pound;0</td>';
            vData.tableHTML = vData.tableHTML + '<td>&pound;0</td>';
            vData.tableHTML = vData.tableHTML + '<td>&pound;0</td>';
            vData.tableHTML = vData.tableHTML + '<td>&pound;0</td>';
            vData.tableHTML = vData.tableHTML + '<td>&pound;0</td>';
            vData.tableHTML = vData.tableHTML + '<td>&pound;0</td>';
            vData.tableHTML = vData.tableHTML + '</tr>';
        }
    }
    vData.tableHTML = vData.tableHTML + '</tbody></table>';
    document.getElementById("dataTableDiv").innerHTML = '';
    document.getElementById("dataTableDiv").innerHTML = vData.tableHTML;

    delete vData.fileName;
    delete vData.tableHTML;
    delete vData.fileTextLineSplit;
    delete vData.rowEven;
    delete vData.fileTextSplit;
    delete vData.fileText;
    delete vData.BlockCount;
    delete vData.BlockNum;
    delete vData.BlockLetter;
    delete vObject.rawFile;
    delete vData.arrayCount;
};

I have tried using pure javascript, jquery, and a combination of the two to clear out the table and reimport the data with no reduction in memory usage.

I'm still learning and so not especially versed with Java so I may be missing something simple. I've seen many forums (old but relevant) which state that tables in IE have always been a bit iffy, but nothing recent and no actual solutions. It may be that it's the HTA environment which is causing the issue, but I've no way of proving it as everything is offline so I can't perform a local XML in IE due to security restrictions.

Any help would be greatly appreciated

Edit

Just a quick edit; I have tried making use of JQuerys .remove() and.empty() function also but to no avail. The reason I am setting the variables to object arrays (I think that terminology is correct) is that I am able to use the delete function as I assumed it was the variables hogging the memory.

AranDG
  • 406
  • 4
  • 16
  • I wouldn't be surprised if the memory leaks originates in `document.getElementById("dataTableDiv").innerHTML = vData.tableHTML;` due to how IE renders and the performance issues I've seen in the past in render large amounts of dynamic data. – user692942 Nov 05 '15 at 11:46
  • Although you are using IE 11 you may find this interesting - [A memory leak occurs when the InnerHTML property of an element is updated repeatedly in Internet Explorer 8](https://support.microsoft.com/en-us/kb/975623). I wonder what engine the `mshta.exe` uses? – user692942 Nov 05 '15 at 11:53
  • Might also find this interesting - [.append VS .html VS .innerHTML performance](http://stackoverflow.com/q/18393981/692942) one of the [answers](http://stackoverflow.com/a/18394171/692942) directly references JQuery source for the `html()` function which has a comment related to `innerHTML` along the lines of `// Remove element nodes and prevent memory leaks`. – user692942 Nov 05 '15 at 12:13
  • In terms of performance you might find [this answer](http://stackoverflow.com/a/18394159/692942) of interest uses an Array to speed up the process. – user692942 Nov 05 '15 at 12:21
  • @Lankymart Yes this is where the memory leak originates, as stated I previously assumed it was in the ActiveXObject, but unfortunately not as that would have been a quick fix. I believe mshta.exe should utilise whichever engine is currently installed, I've tried it on machines with IE9 and IE11 and both return the same issue. And yes, although the append() method is faster when running, it didn't affect my memory leak issue unfortunately, but I will use this method of integration in future. Thank you for your suggestions thus far though – AranDG Nov 05 '15 at 14:50
  • Not may not be true you might need to use `X-UA-Compatible` to set the HTA application to use `Edge` mode, by default HTAs use Compatibility mode according to [this answer](http://stackoverflow.com/a/11728073/692942) from [How to get IE9 standards support for dialogs opened by HTA?](http://stackoverflow.com/q/11727815/692942). Also in regards to `append()` it isn't faster it's slower then `innerHTML()` if you go off the tests in that SO answer. – user692942 Nov 05 '15 at 14:54
  • unfortunately I already use that tag when creating HTAs as I've stumbled across certain CSS3 grid system issues without it. Tag for reference – AranDG Nov 05 '15 at 14:56
  • Have you checked that `delete` is actually doing what you expect? From the [MSDN docs](https://msdn.microsoft.com/en-us/library/2b2z052x(v=vs.94).aspx) - *"If the result of expression is an object, the property specified in expression exists, and the object will not allow it to be deleted, `false` is returned. In all other cases, `true` is returned."*. As you don't check the return value of `delete` do you know they are actually being removed? – user692942 Nov 05 '15 at 15:02
  • Yes, I went down that road initially. Once deleted, the variable returns as undefined. I even tried adding ='' and =null before each delete and still no change in the memory usage. – AranDG Nov 05 '15 at 15:04
  • Well that's me out of ideas. If it is an inherent issue with the `innerHTML` property leaking memory I'm not sure how you would fix it. – user692942 Nov 05 '15 at 15:08
  • Yeah, same boat unfortunately. I can probably work around it using aligned divs in a grid system, it's just going to be dirty code is all. Thank you for your help on this though, at least I know it's not something simple I've just overlooked – AranDG Nov 05 '15 at 15:11

0 Answers0