Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

    Possible memory leak in datasource.fetchData

    Hello Isomorphic!

    I am using Smartclient v9.0p_2014-01-23/PowerEdition Deployment (built 2014-01-23)
    Browsers IE11, Chrome 37.

    In a long running application which fetches data every second, I noticed that memory consumption increases constantly.

    See the following testcase:

    Code:
    "use strict";
    // Functions
    function f(){
    	memorytest.fetchData(
    		null,
    		callback, 
    		{operationId:"SQL"}
    	);
    	Timer.setTimeout (f, 1000);
    }
    
    function callback (dsRequest, data, dsResponse) {
    	// do nothing
    }
    
    // Main
    f();
    Datasource definition is
    Code:
    <DataSource 
    	schema="dbo"
    	dbName="tooltronic"
    	ID="memorytest"
    	tableName="measurement"
    	serverType="sql"
    >
        <fields>
            <field name="measurementId"		type="integer"	/>
    		<field name="rawData"   		type="text"/>
        </fields>
    	
    	<operationBindings>
    		<operationBinding operationType="fetch" operationId="SQL">
    			<customSQL>	select TOP 500 * from dbo.measurement
    			</customSQL>
    		</operationBinding>
    	</operationBindings>	
    </DataSource>
    rawdata is a string with about 10,000 chars.

    Memory consumption is increasing until the browser crashes.
    If the select statement results in an emty recordset memory is stable.

    Please investigate or give me a hint if something has to be changed.

    Best regards
    John


    Addendum:
    =======
    In the meantime I did a test with RPCManager.sendRequest with the same result.
    Memory consumption with the following testcase is about 4MB per minute, increasing until the browser crashes.

    Testcase for RPCManager.sendRequest

    Code:
    "use strict";
    // Functions
    function f(){
    
    	RPCManager.sendRequest({
    		data:null,
    		callback: function (rpcResponse, data, rpcRequest){
    			// do nothing
    		},
    		actionURL: "rpc.jsp"
    	});	
    	
    	Timer.setTimeout ("f()", 250);
    }
    
    // Main
    f();
    Sample JSP file
    Code:
    <html><body>
    <%@ page import = "com.isomorphic.rpc.*" %>
    <%
    	RPCManager rpc = new RPCManager(request, response, out);
    	rpc.send("answer");
    %>
    </body></html>
    Last edited by john_austria; 31 Aug 2014, 07:00. Reason: Addendum: Test with RPCManager

    #2
    We get many false reports of memory leaks, which are actually created by developer tools, browser plugins, etc.

    First, update to a recent version (9.1 latest patched build from smartclient.com/builds). Then, make sure you can reproduce the leak on a machine that has a fresh OS + browser install, nothing else installed, no developer tools active.

    Also correct your DOCTYPE (see FAQ). IE will leak if you set the wrong DOCTYPE, and this is not fully correctable by a framework (any framework, not just SmartClient).

    Comment


      #3
      So, in the meanwhile I tested on an fresh installed Win7 with IE11 and SmartClient v9.1p_2014-09-01/PowerEdition Deployment (built 2014-09-01).

      The result ist exactly the same, leaking memory until the browser crashes.

      I did the same test with "useSimpleHttp: true" with the same results.

      Then I switched over to a native XMLHttpRequest, and, o wonder, memory consumption was stable.

      This is my last and very simple testcase, reduced to call RPCManager.sendRequest with useSimpleHttp=true in a loop.

      Memory leakage in this case is 1 MB.

      File memorytest.jsp
      Code:
      <!DOCTYPE html>
      
      <%@ page contentType="text/html; charset=UTF-8"%>
      <%@ taglib uri="/WEB-INF/iscTaglib.xml" prefix="isomorphic" %>
      
      <HTML><HEAD>
      </HEAD><BODY>
      <isomorphic:loadISC />
      <SCRIPT SRC=memorytest.js> </SCRIPT>
      </BODY></HTML>
      File memorytest.js
      Code:
      "use strict";
      function f(){
      
      	var i=0;	
      	for (i=0; i < 1000; i++) {		
      		RPCManager.sendRequest({
      			data:null,
      			useSimpleHttp: true,
      			callback: function (rpcResponse, data, rpcRequest){
      				//do nothing
      			},
      			actionURL: "rpc1.jsp"
      		});
      	}
      }
      
      isc.IButton.create({
      	ID: "Start",
      	title: "Start",
      	click: "f()"
      });
      File rpc1.jsp
      Code:
      <%= "answer" %>

      Comment


        #4
        We triple-checked in case IE11 had introduced yet a new bug, but as expected, there is no leak.

        As previously stated, you may have enabled development tools, including IE11's built-in tools (the ones that appear when you hit F12) or RPC tracking in the Developer Console's RPC tab.

        Note that you do need to remove "use strict" as unfortunately in strict JavaScript mode IE prevents us from gathering key diagnostics. But this wouldn't create a leak either way.

        Comment


          #5
          Thank you.
          The crucial clue was in the last post.

          RPC tracking caused the memory consumption.

          Even if the Developer Console has not been opened, the tracking was turned on. That was new to me, but makes perfect sense while developing the application. The developer console gathers information in the background as it should be.

          Without RPC tracking the memory usage remains constant.

          Thanks again for the hint.

          John

          Comment


            #6
            Is there a way to determine if RPC tracking is on without opening up the Developer Console?

            Comment


              #7
              There's no documented or supported way to do this, but if you are adventurous, the code is in RPCManager.js, method setTrackRPC().

              Comment


                #8
                OK. Thanks for the response.

                So it would never be turned on unless it had been done so explicitly like from the Developer Console correct?

                I am just trying to make sure we don't have it turned on somehow in a production environment.

                Comment


                  #9
                  Right. Also, the setting is tracked in a cookie, so it's a per-developer (or really, per-installed-browser) setting. So there's no way to accidentally "have it turned on" in a particular deployment.

                  Comment


                    #10
                    Excellent thanks for the response!

                    Comment


                      #11
                      Hello Isomorphic!

                      After a successful test with RPCManager.sendRequest I have returned to the test with a DataSource.
                      Unfortunately, I discovered that it still has a memory leak there.

                      After some debugging I found the following cause:

                      In the ISC_DataBinding.js file each request is stored in the array "_clientCustomRequests". Even if it is an "iscServer" request.
                      ("this._storeCustomRequest" is called in sendDSRequest, line 19093).

                      But the entry will not be deleted unless it is in fact a custom request.
                      As long as the DataSource exists, every request is collected in this array and increases heap memory.

                      Please investigate.
                      Thanks,
                      John

                      Smart Client Version: v9.1p_2014-09-01 / Power Edition Deployment (built 2014-09-01)

                      Comment


                        #12
                        There is code elsewhere (getServiceInputs(), and processResponse()) that removes the request from this internal array, as expected.

                        We've already verified leakless operation here (multiple times..) so if you think you've got a leak, we need a standalone test case that demonstrates the leak.

                        Comment


                          #13
                          Yes, I've seen it.
                          But both functions are not called at a request to the SC server. (see code fragment below).
                          I'll create a test case in the next few days.
                          John

                          Code:
                          Fragment from sendDSRequest : function (dsRequest)  line 19143
                          
                          	// detect whether this is a clientOnly request
                          	if ( dsRequest.shouldUseCache === false ||
                          		(dsRequest.shouldUseCache !== true) &&
                          		!this.clientOnly &&
                          		(!this.cacheAllData || dsRequest.downloadResult || dsRequest.cachingAllData ||
                          		 (dsRequest.operationType != null && dsRequest.operationType != "fetch") ||
                          		 (dsRequest.operationType == "fetch" && this.cacheAllOperationId &&
                          			 this.cacheAcrossOperationIds == false &&
                          			 dsRequest.operationId != this.cacheAllOperationId)))
                          	{
                          		// not client-only: this is a request to the SC server
                          
                          		if (this.logIsInfoEnabled("cacheAllData") && dsRequest.cachingAllData) {
                          			// special request from a cacheAllData DataSource to populate cache
                          			this.logInfo("sendDSRequest: processing cacheAllData request", "cacheAllData");
                          		}
                          
                          		this.addDefaultCriteria(dsRequest, this.getOperationBinding(dsRequest));
                          		this.applySendExtraFields(dsRequest);
                          
                          		var operationBinding = this.getOperationBinding(dsRequest);
                          		if (operationBinding == null) operationBinding = {};
                          		var defaultParams = operationBinding.defaultParams || this.defaultParams;
                          		if (defaultParams) {
                          			dsRequest.data = isc.addProperties({}, defaultParams, dsRequest.data);
                          		}
                          		data = dsRequest.data;
                          		
                          		==> function returns here in my case
                          		return this.performSCServerOperation(dsRequest, data);
                          	}
                          }
                          ==> never reached in my case
                          var inputs = this.getServiceInputs(dsRequest);

                          Comment


                            #14
                            Sorry for the long delay, here is my testcase:

                            Code:
                            <!DOCTYPE html>
                            
                            <%@ page contentType="text/html; charset=UTF-8"%>
                            <%@ taglib uri="/WEB-INF/iscTaglib.xml" prefix="isomorphic" %>
                            
                            <HTML>
                            <HEAD></HEAD>
                            <BODY>
                            <isomorphic:loadISC useDebugModules="true"/>
                            <SCRIPT>
                            	<isomorphic:loadDS ID="memorytest"/>
                            </SCRIPT>
                            
                            <SCRIPT> 
                            function f(){
                            	for (i=0; i<10; i++) {
                            		memorytest.fetchData(
                            			null,
                            			callback, 
                            			{operationId:"SQL"}
                            		);
                            	}
                            }
                            
                            function callback (dsRequest, data, dsResponse) {
                            	// do nothing
                            }
                            
                            isc.IButton.create({
                            	ID: "Start",
                            	title: "Start",
                            	click: "f()"
                            });
                            
                            </SCRIPT>
                            </BODY></HTML>
                            Datasource:
                            Code:
                            <DataSource 
                            	schema="dbo"
                            	dbName="tooltronic"
                            	ID="memorytest"
                            	tableName="measurement"
                            	serverType="sql"
                            >
                                <!--
                            	<fields>
                                    <field name="measurementId"		type="integer"	/>
                            		<field name="rawData"   		type="text"/>
                                </fields>
                            	-->
                            	
                            	<operationBindings>
                            		<operationBinding operationType="fetch" operationId="SQL">
                            			<customSQL>	select GETDATE()
                            			</customSQL>
                            		</operationBinding>
                            	</operationBindings>	
                            </DataSource>
                            Every click to Start increases the heap with 10 elements named memorytest_request12, ...13, ...14, and so on.

                            I have set a breakpoint on "delete this._clientCustomRequests", but it was never called.

                            Important: This issue occurs only with a call to iscServer.

                            Comment


                              #15
                              Just a note to let you know this leak should be entirely resolved in the next nightly build (dated Sep 24 or above, in branches 9.1p, 10.0p and 10.1d)

                              Regards
                              Isomorphic Software

                              Comment

                              Working...
                              X