Memory Leak
Memory Leak
amir.soofi
Posts: 5Questions: 0Answers: 0
Has anyone noticed that there appears to be a memory leak in TableTools 2.0.0 and 2.0.1 in IE7 and in IE8?
I loaded a simple page in IE with no other IE tabs or windows:
http://www.datatables.net/release-datatables/extras/TableTools/index.html
And watched the Task Manager for the only iexplore.exe process level off at about 3% of CPU and go up a few KB of memory every few seconds. I left it overnight and it was pretty big by the morning (went from 36MB to 70MB).
I tried it with Flash 10.1 and 10.2, just in case.
Any thoughts? Anyone else see similar behavior?
I loaded a simple page in IE with no other IE tabs or windows:
http://www.datatables.net/release-datatables/extras/TableTools/index.html
And watched the Task Manager for the only iexplore.exe process level off at about 3% of CPU and go up a few KB of memory every few seconds. I left it overnight and it was pretty big by the morning (went from 36MB to 70MB).
I tried it with Flash 10.1 and 10.2, just in case.
Any thoughts? Anyone else see similar behavior?
This discussion has been closed.
Replies
Thanks,
Allan
By morning, IE had gone from 32MB to 900MB.
Is there a particular part of the JavaScript that runs continuously or on some interval? I can try to drop a breakpoint there.
I loaded the page in a debugger in Visual Studio, where it appeared that IE was loading and unloading some file every few seconds. It loads and unloads too quickly to know what it is.
How about the SWF? Is it loading anything repetitively?
This was introduced in 2.0.1 to fix a bug with IE (see the comment in the code) and this is what I suspect might be causing the issue (although is won't be if the issue is present in 2.0.0 since this was new code). I've absolutely no idea why there would be a file being loaded an unloaded though - that's very odd! Does Visual Studio provide a trace that might allow identification of the file?
Allan
Also, it's not a file that repeatedly loads in Visual Studio, it's some kind of code block.
So yeah, I think you identified the cause. Some object that tracks callbacks is growing without bound.
I know you have no immediate way to know if callbacks were removed from ExternalInterface, and I know the underlying __flash__removeCallback("obj_id", "callback_name") is not exposed so you can't explicitly remove before adding, but tell me if this will work:
Register a new dummy callback "hasCallbacks" that returns true. On interval, run ExternalInterface.call("hasCallbacks"). If true, great. But "If the function is not available, the call returns null" according to Adobe docs. If it's null, then run addCallbacks.
What do you think? If I'm way off here, let me know.
Visual Studio, when attached to IE loading a page with one DataTable running TableTools in the simplest case, reports on what files are currently loaded and available.
In addition to the usual cocktail of jquery.js, jquery.dataTables.js, ZeroClipboard.js, and TableTools.js, there are also "JScript - script block" items for any inline JavaScript code.
In the simple case of TableTools 2.0.0, using the copy_cvs_xls_pdf.swf, there are 4 "JScript - script block" items loaded:
They all have the same code:
[code]
function __flash__arrayToXML(obj) {
var s = "";
for (var i=0; i
I dropped a breakpointer in __flash__addCallback, and I was able to step through to see the new JScript contents:
[code]
__flash__addCallback(document.getElementById("ZeroClipboardMovie_3"), "setHandCursor");
[/code]
and then the next file:
[code]
__flash__addCallback(document.getElementById("ZeroClipboardMovie_3"), "clearText");
[/code]
and then...
repeat ad nauseum.
So these script blocks are the code produced from the eval statement in __flash__addCallback.
According to Visual Studio, these script blocks load and unload, so I would assume that it's not the script block itself that is causing the memory bloat. My guess, is that the call to instance.CallFunction or __flash__argumentToXML is grabbing memory and not giving it back.
But who knows ... I'm not even remotely a flash developer.
I hope I did enough research on this to be useful.
I'll address this for the 2.0.2 TableTools release. Thanks again for the help!
Regards,
Allan
I encountered the same problem on IE8. In Firefox, Opera and IE9 everything just works fine.
Its the exact same JScript function that produces the javascript error (Object expected).
I also found out that it always happens on the SECOND time I include a DataTable with TableTools.
If you search the web for "__flash__addCallback" you'll see that the problem seems to occur on other occasions too.
@billhuber - The problem is that the 2.0.0 version of the SWF has a bug in it (well - really it's a bug in IE...) whereby if you make the control display:none, IE will loose the attached event handlers. As such, it needs to cycle adding the event handlers - which appears to be leaking (according to the Adobe documentation it really shouldn't - this is a perfectly valid thing to do - but none the less it is). I've been working on a way to address this of late, but it is still far from perfect as it is not proving to be a trivial problem to solve...
Allan
I see a javascript error "Object expected" when the following script block gets loaded on IE 8 because document.getElementById("ZeroClipboardMovie_3") returns null the second time (and subsequent times) I load the grid. I am using TableTools v2.0.1. Should I use TableTools v2.0.0 to get around this issue?
function __flash__addCallback(instance, name) {
instance[name] = function () {
return eval(instance.CallFunction("" + __flash__argumentsToXML(arguments,0) + ""));
}
}
_flash__addCallback(document.getElementById("ZeroClipboardMovie_3"), "setAction");
Rajesh
Allan
I don't know if this has got with anything of the above, but i found out a peculiar behavior when assigning 2 tabletools to one datatable. the code is this:
[code]
var oDTctl00_ContentPlaceHolder1_GridAcionamentosOperador = $('#ctl00_ContentPlaceHolder1_GridAcionamentosOperador').dataTable({
"bJQueryUI": false
, "bSortClasses ": false
, "bDeferRender": true
, "iDeferLoading": 1
, "bProcessing": true
, "aaSorting": []
, "bAutoWidth": false
, "oLanguage": {
"sProcessing": "Processando...",
"sLengthMenu": "Mostrar _MENU_ registros",
"sEmptyTable ": "Não foram encontrados resultados",
"sZeroRecords": "Não foram encontrados resultados",
"sInfo": "Mostrando de _START_ até _END_ de _TOTAL_ registros",
"sInfoEmpty": "Mostrando de 0 até 0 de 0 registros",
"sInfoFiltered": "(filtrado de _MAX_ registros no total)",
"sInfoPostFix": "",
"sInfoThousands": ".",
"sSearch": "Buscar:",
"sUrl": "",
"oPaginate": {
"sFirst": "",
"sPrevious": "",
"sNext": "",
"sLast": ""
}
}
, "aoColumnDefs": [
{ "bSortable": false, "aTargets": [ 0,1 ] }
]
, "bStateSave": true
, "iCookieDuration": 60*60*12
, "bPaginate": false, "bLengthChange": false
, "sDom": 'RCTV<"clear">fr<"DTTT_OpenClose_container">ti'
, "oColReorder": { "aiOrder": [0,1,2,3,4,5,6,7] }
, "oColVis": { "buttonText": "Colunas", "bRestore": true, "sRestore": "Restaurar", "sAlign": "right", "sSize": "css", "activate": "mouseover"
, "aiExclude": [ 0,1 ] }
, "oTableTools": {
"sSwfPath": "../scripts/jquery/js/../swf/copy_cvs_xls_pdf.swf",
"aButtons": [
{ "sExtends": "print", "sButtonText": "Impressão", "mColumns": "visible", "sToolTip": "Impressão",
"sMessage": "",
"sInfo": "ImpressaoPor favor utilizar a funcionalidade de impressão do browser para imprimir esta tabela. Pressione ESC (escape) quando terminar." }
, { "sExtends": "copy", "sButtonText": "Clipboard", "mColumns": "visible", "fnClick": function ( nButton, oConfig, oFlash ) { oDTctl00_ContentPlaceHolder1_GridAcionamentosOperador.fnSetColumnVis( 0, true, false ); oDTctl00_ContentPlaceHolder1_GridAcionamentosOperador.fnSetColumnVis( 1, true, false ); this.fnSetText( oFlash , this.fnGetTableData(oConfig) );}, "fnComplete": function ( nButton, oConfig, oFlash ) { oDTctl00_ContentPlaceHolder1_GridAcionamentosOperador.fnSetColumnVis( 0, false, false ); oDTctl00_ContentPlaceHolder1_GridAcionamentosOperador.fnSetColumnVis( 1, false, false ); var lines = text.split('\n').length, len = oDTctl00_ContentPlaceHolder1_GridAcionamentosOperador.nTFoot === null ? lines-1 : lines-2, plural = (len==1) ? "" : "s"; alert( 'Copied '+len+' row'+plural+' to the clipboard' ); } },
{ "sExtends": "csv", "sButtonText": "CSV", "mColumns": "visible", "bFooter": false , "bHeader": false, "fnClick": function ( nButton, oConfig, oFlash ) { oDTctl00_ContentPlaceHolder1_GridAcionamentosOperador.fnSetColumnVis( 0, true, false ); oDTctl00_ContentPlaceHolder1_GridAcionamentosOperador.fnSetColumnVis( 1, true, false ); this.fnSetText( oFlash , this.fnGetTableData(oConfig) );}, "fnComplete": function ( nButton, oConfig, oFlash ) { oDTctl00_ContentPlaceHolder1_GridAcionamentosOperador.fnSetColumnVis( 0, false, false ); oDTctl00_ContentPlaceHolder1_GridAcionamentosOperador.fnSetColumnVis( 1, false, false ); } },
{ "sExtends": "xls", "sButtonText": "XLS", "mColumns": "visible", "sTitle": "", "fnClick": function ( nButton, oConfig, oFlash ) { oDTctl00_ContentPlaceHolder1_GridAcionamentosOperador.fnSetColumnVis( 0, true, false ); oDTctl00_ContentPlaceHolder1_GridAcionamentosOperador.fnSetColumnVis( 1, true, false ); this.fnSetText( oFlash , this.fnGetTableData(oConfig) );}, "fnComplete": function ( nButton, oConfig, oFlash ) { oDTctl00_ContentPlaceHolder1_GridAcionamentosOperador.fnSetColumnVis( 0, false, false ); oDTctl00_ContentPlaceHolder1_GridAcionamentosOperador.fnSetColumnVis( 1, false, false ); } },
{"sExtends": "collection", "sButtonText": "PDF", "sButtonClass": "DTTT_button_pdf", "sButtonClassHover": "DTTT_button_pdf_hover", "aButtons": [
{ "sExtends": "pdf", "sButtonText": "Retrato", "sButtonClass": "DTTT_button_text", "sButtonClassHover": "DTTT_button_text_hover", "mColumns": "visible", "sNewLine": "auto", "sTitle": "", "fnClick": function ( nButton, oConfig, oFlash ) { oDTctl00_ContentPlaceHolder1_GridAcionamentosOperador.fnSetColumnVis( 0, true, false ); oDTctl00_ContentPlaceHolder1_GridAcionamentosOperador.fnSetColumnVis( 1, true, false ); this.fnSetText(oFlash , "title:" + this.fnGetTitle(oConfig) + "\n" + "message:" + oConfig.sPdfMessage + "\n" + "colWidth:" + this.fnCalcColRatios(oConfig) + "\n" + "orientation:" + oConfig.sPdfOrientation + "\n" + "size:" + oConfig.sPdfSize + "\n" + "--/TableToolsOpts--\n" + this.fnGetTableData(oConfig)); }, "fnComplete": function ( nButton, oConfig, oFlash ) { oDTctl00_ContentPlaceHolder1_GridAcionamentosOperador.fnSetColumnVis( 0, false, false ); oDTctl00_ContentPlaceHolder1_GridAcionamentosOperador.fnSetColumnVis( 1, false, false ); } },
{ "sExtends": "pdf", "sButtonText": "Paisagem", "sButtonClass": "DTTT_button_text", "sButtonClassHover": "DTTT_button_text_hover", "mColumns": "visible", "sNewLine": "auto", "sPdfOrientation": "landscape", "sTitle": "", "fnClick": function ( nButton, oConfig, oFlash ) { oDTctl00_ContentPlaceHolder1_GridAcionamentosOperador.fnSetColumnVis( 0, true, false ); oDTctl00_ContentPlaceHolder1_GridAcionamentosOperador.fnSetColumnVis( 1, true, false ); this.fnSetText(oFlash , "title:" + this.fnGetTitle(oConfig) + "\n" + "message:" + oConfig.sPdfMessage + "\n" + "colWidth:" + this.fnCalcColRatios(oConfig) + "\n" + "orientation:" + oConfig.sPdfOrientation + "\n" + "size:" + oConfig.sPdfSize + "\n" + "--/TableToolsOpts--\n" + this.fnGetTableData(oConfig)); }, "fnComplete": function ( nButton, oConfig, oFlash ) { oDTctl00_ContentPlaceHolder1_GridAcionamentosOperador.fnSetColumnVis( 0, false, false ); oDTctl00_ContentPlaceHolder1_GridAcionamentosOperador.fnSetColumnVis( 1, false, false ); } }
]}
]}
});
oDTctl00_ContentPlaceHolder1_GridAcionamentosOperador.fnSearchHighlighting();
oDTctl00_ContentPlaceHolder1_GridAcionamentosOperador.fnFilterOnReturn();
oDTctl00_ContentPlaceHolder1_GridAcionamentosOperador.rowGrouping({
bSetGroupingClassOnTR: false
, iGroupingColumnIndex: 0
, bExpandableGrouping: true
, iGroupingColumnIndex2: 1
});
var oTableTools = new TableTools(oDTctl00_ContentPlaceHolder1_GridAcionamentosOperador, { "aButtons": [
{ "sExtends": "text", "sAction": "text", "sButtonText": "", "sButtonClass": "DTTT_button_openclose", "sButtonClassHover": "DTTT_button_openclose_hover", "mColumns": "visible" },
{ "sExtends": "text", "sAction": "text", "sButtonText": "", "sButtonClass": "DTTT_button_openclose", "sButtonClassHover": "DTTT_button_openclose_hover", "mColumns": "visible" }
]});
oDTctl00_ContentPlaceHolder1_GridAcionamentosOperador.find('.DTTT_OpenClose_container').append( oTableTools.dom.container );
new FixedHeader(oDTctl00_ContentPlaceHolder1_GridAcionamentosOperador);
[/code]
as you can see i add a second table tool with 2 text buttons and here is where this get strange.
first i don't see the second tooltable within the html markup. but when i debug i find that the browser is looping inside tatbletools.js in _fnglue trying to set the collection buttons of the first tabletool.
let me add that i don' get any error during debug.
Allan
Allan
Jim
Allan
Jim
First of all I want to tell you that DataTables is a truly remarkable plugin. I have tried other client side solutions to rendering tabular data and none of them compare to what you have here. Many thanks for all your hard work. Now about my issue... (FYI my app works great in Firefox, unfortunately we have to support IE8 for now....
I am also reloading the TableTools dynamically which is when the exception is thrown. I believe that the solution to this issue may be found at the website below -
http://zaalabs.com/2011/01/adobe-flash-externalinterface-issues-with-internet-explorer/
Same issue just different application.
What worked for this developer was to rename the following -
ExternalInterface.addCallback("stop", stop); to ExternalInterface.addCallback("stopSong", stop); as he suspected that the word "stop" is a reserved name in IE8.
In fact you can find many blog postings about this causing problems in lots of apps by pasting in
function __flash__addCallback(instance, name) into Google.
I have tried to decompiling the copy_cvs_xls_pdf.swf so that I can make changes to your action script (I am assuming that the action script used by the .swf file is ZeroClipboardPdf.as ?) and rebuild the swf file. So far I have not been able to rebuild the .swf and decided that I would turn to you for assistance at this point....
When I look at the .fla file (I have tried using DecompileFlash which appears to do the job correctly) but when I load the .fla file it tells me it does not have any action script included as a resource. I have not done any flash development for years but I do have the tools (using Adobe Flash Professional CS3). Can you provide all of the swf components and the steps to rebuild?
I am thinking that perhaps you have are inadvertently using a IE8 reserved word also - perhaps "setHandCursor" ? so my idea was to change the action script so that it uses a different name seeing that this solution has worked for other apps. The code that is causing the object not found exception is below - the first exception shows that the (instance is null - and the name is setHandCursor)
- this is the IE8 generated code that throws the object not found exception when debugging in visual studio
function __flash__addCallback(instance, name) {
instance[name] = function () {
return eval(instance.CallFunction("" + __flash__argumentsToXML(arguments,0) +
""));
}
Here is your action script we are referreing to -
/* External functions
* This is extremely nasty, and I'm far from proud of this, however, when a Flash
* movie is hidden in IE (i.e. display:none) then all callbacks are removed, and there
* is no way to tell that this has happened! Javascript can't tell us since there are
* no callbacks - so we need to add them again and again... Fortunatly Flash doesn't
* allow multiple callback functions to be used with each callback name, it just uses
* the provided function, so the only thing we use for this workaround is a couple of
* clock cycles.
*/
addCallbacks();
setInterval( addCallbacks, 1000 );
// signal to the browser that we are ready
ExternalInterface.call( 'ZeroClipboard.dispatch', domId, 'load', null );
}
public function addCallbacks ():void {
ExternalInterface.addCallback("setHandCursor", setHandCursor); -- *first exception
ExternalInterface.addCallback("clearText", clearText);
ExternalInterface.addCallback("setText", setText);
ExternalInterface.addCallback("appendText", appendText);
ExternalInterface.addCallback("setFileName", setFileName);
ExternalInterface.addCallback("setAction", setAction);
ExternalInterface.addCallback("setCharSet", setCharSet);
ExternalInterface.addCallback("setBomInc", setBomInc);
}
Below is my DataTable function and the ajax function InitiateSearch that uses it - everything is created on the fly based on the users selection of what columns they want included.
function InitiateSearch() {
var DataRequest = ReportValues.join("|");
var MyData = "{ datarequest:\"" + DataRequest + "\"\}";
$.ajax({
type: "POST",
url: "../Services/SearchWS.asmx/SearchRequest",
data: MyData,
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (msg) {
var ret = msg.d;
CreateDynamicTableHeader();
RenderDataTable();
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
alert("ajax call failed during search request = " + textStatus);
}
}); // ajax post close
}
function RenderDataTable() {
var FileNameForSearch = "";
var username = "";
username = $("input[id$=hdnLoggedInUser]").val();
FileNameForSearch = "SearchData_" + username + "_" + ".txt";
$('#tblSearchResults').dataTable({
"bJQueryUI": true,
"bProcessing": true,
"sScrollY": "200px",
"bDestroy": true,
"bDeferRender": true,
"sAjaxSource": "../sources/" + FileNameForSearch,
"sDom": '<"H"Tfr>tS<"F"i>',
"oTableTools": {
"sSwfPath": "../TableTools/media/swf/copy_cvs_xls_pdf.swf",
"sRowSelect": "single",
"aButtons": ["copy", "csv", "xls", "pdf"]
}
});
$('#DivSearchPastEntriesResult').show();
} // close function
So if you could assist me in getting this resolved it would be most appreciated - anyone who has to support IE will have this issue if they reload the swf....
Alternative solutions that would still enable me to use the xls, csv and pdf features which are critical to my
deployment would also be more than welcome. Many thanks in advance to you or anyone out there who can finally solve this !
@import "css/DataTables/demo_table.css";
@import "css/DataTables/demo_page.css";
@import "css/DataTables/demo_table_jui.css";
@import "Plug-Ins/TableTools/media/css/TableTools_JUI.css";
Here is my table definition:
dataTableOjb = $("#DailyOrderingTbl").dataTable({
"sDom": 'T<"clear">lfrtip',
"aaData": dtData,
"bJQueryUI": true,
"iDisplayLength": 100,
"aLengthMenu": [[20, 50, 100, -1], [20, 50, 100, "All"]],
"bProcessing": true,
"bDestroy": true,
"oLanguage": {
"sEmptyTable": "No matching records found",
"sLoadingRecords": "Please wait - loading..."
},
"sPaginationType": "full_numbers",
"oTableTools": {
"sSwfPath": "Plug-Ins/TableTools/media/swf/copy_cvs_xls_pdf.swf",
"aButtons": [
"copy",
"csv",
"xls",
"pdf",
"print"
]
}
});
Could you possibly try these SWF files:
http://datatables.net/clients/lanativelea/copy_cvs_xls_pdf.swf
http://datatables.net/clients/lanativelea/copy_cvs_xls.swf
These are the latest SWF files which will work with the TableTools nightly ( http://datatables.net/download ) - i.e. newer that those included in the distribution package.
To compile the SWFs yourself, you need to download the Flex SDK from Adobe (its free :-) ) and then the two AS files should be all you need, but it would be good to get to the bottom of this. I don't actually have access to IE8 at the moment (and probably for the rest of the week), so I can't debug it directly, but if you could let me know how you get on with the two files above that would be great.
Thanks,
Allan
Allan - thanks for posting those alternate versions - did seem to improve (I can now create different tables dynamically without IE8 actually stopping execution) however.....
I am also still getting the error - although it appears to be a different one (505) , also the export does not work with these versions (IE or FireFox) no data is being written into the spreadsheet or PDF now - just writes the headers... I will be looking deeper into this later today no time right now. Dvnandover - I really need to get this working by the end of the week if not sooner so if you make any progress please let me know and I will do the same - looks like we are doing almost the same thing. In fact if you want to give me a call this evening, I will be working on this from my hotel (in training this week) and we can compare notes - Thanks - 310-906-6682
Edit: I down loaded version 2.0 of the TableTools and the problem gone away. Now Everything worked.
Download:
https://github.com/DataTables/TableTools/tags
I use datatables with TableTools and I have noticed a memory leak. With FF (all versions from 6 to 8), I have the process plugin-container that gain 5kb to 20kb per secondes. With IE, I noticed the same gain for process iexplore.exe and with chrome the plugin-shockwave have the same gain.
I show the same problem on your demo page http://datatables.net/extras/tabletools/
I tried to compile ZeroClipboard.as to trace all functions and I add 'console.log' on all functions in ZeroClipboard.js and TableTools.js but I show no trace of reccurent call.
After one nigth, FF reach 1.5Gb and block the machine.
I don't understand why I have this problem.
Have you some idea?
Mickael
I'm also getting the memory leak problem in IE9 on your demo page. Any updates on this? As it is, this basically makes Tabletools impossible to implement.
Allan