OpenEdge 11.6 | How to find a memory leak on AppServer - Forum - OpenEdge Development - Progress Community

OpenEdge 11.6 | How to find a memory leak on AppServer

 Forum

OpenEdge 11.6 | How to find a memory leak on AppServer

This question is not answered

Hello All,

We're investigating a memory leak in our application.

Is there any utility or any setting which will report the memory leaks in the AppServer source code.

Any tips on how to tackle this kind of issues is appreciated!

Regards,

Atul Dalvi

All Replies
  • Hello Daniel,

    No, I have not worked with swagger.

    Can you give some more details on it?

    And as I said I have few datasets defined in my programs but those are normal ones, no dynamic handles for datasets or output parameter handles.

    How swagger will help into this?

  • Hi,

    First sorry for my English. I'm using google translator and I hope you can understand.

    I believe that with swagger you will be able to identify the program that is causing the memory leak and know which DATASET is not being removed.

    I solved my memory leak problem with swagger help where the programs were adjusted in front of your report.

    The following is the step-by-step guide for you to enable and use swagger

    - Step 1 - Enable OEmanager

    cd /usr/wrk/instance

    bin/tcman.sh undeploy -u tomcat:yourpasswod oemanager     - Password default - tomcat

    bin/tcman.sh deploy -u tomcat:yourpassword -a oemanager /$DLC/servers/pasoe/extras/oemanager.war

    vi webapps/oemanager/WEB-INF/oemgrSecurity-container.xml

    //remove comments in line 35 <!-- Access to SwaggerUI. Disabled by default, user has to uncomment the below line to enable it -->

    :wq

    Sign in - hostname:port-instcance/manager/     -  do not forget / at the end

    /oemanager  - Stop and Start

    - Step 2 - Collect Agent ID

    Sign in - hostname:port-instcance/oemanager/     - do not forget / at the end   - Usr: tomcat / Pwd: your password

    Click "Get / application/{appName}/agents Get Agents"

    Click "Try it out"

    Inform Instance name and execute

    copy "agentID"

    - Step 3 - Enable agent for collection

    Click " PUT /aaplication/{appName}/agents/{agentID}/ABLObjects/status Enable/Disable ABLObjects and click “Try it out”

    Inform instance name and agentID

    Change for

    {

      "enable" : "true"

    }

    And Execute

    Response Body will be changed for: "result": true

    - Step 4 - Run your program or your system normally so that the collection is done

    - Step 5 - Analyze collection

    Click: GET / applications/{appName}/agents/{agentID}/ABLObjects Get ABLObjects Report and click in “Try it out

    The screen below will show the handle used;

    Do it Download

    - Step 6 - Run again your program or your system normally so that the collection is done

    - Step 7 - Analyze collection again

    Click: GET / applications/{appName}/agents/{agentID}/ABLObjects Get ABLObjects Report and click in “Try it out

    The screen below will show the handle used;

    Do it Download

    - Step 8 - Check the reports

    If the handle of the first scan remains, it means that the program is not deleting the memory leak. It should be reviewed and corrected.

    If it disappears and generates another, the program is correct without the addition of memory leak.

    If the number of rows in the report increases, it means that there is memory leak and must be corrected. The handleID should always be refreshed.

    With this tool it is possible to evaluate if the program is having memory leak and correct it. So the memory consumption will drop successfully.

    - Step 9 - Disable agent for collection

    Click " PUT /aaplication/{appName}/agents/{agentID}/ABLObjects/status Enable/Disable ABLObjects and click “Try it out”

    Inform instance name and agentID

    Change for

    {

      "enable" : "false"

    }

    And Execute

    END Step

    I hope you understand and if you have any questions, I am at your disposal.

    Regards

  • Hello,

    Where I can set this -clientlog ? My client is not an OpenEdge client, its a .net client and they call the soap services developed in OpenEdge.

    We just accept inputs from them, process those inputs in OpenEdge and returns back the output in datasets or temp table.

  • Hello,

    My client is also dotnet.

    When you call the dotnet client, it calls a .p program in OpenEdge?

  • Does 11.6 support swagger?

  • I'm in version 11.7

    See if you can enable it in version 11.6

  • Swagger is only available in 11.7.3+. If you are on 11.6, you will not find the API's to find the leaks. They are only available from 11.7.2+ onward. I think the choice for you would be enable DynamicObjects logging in the PASOE logEntryTypes and debug which objects are leaking from the agent log.

    Regards,

    Irfan

  • Wow

  • Hello All,

    On the AppServer source code, we have a code structure like 1 include that contains all its temporary table definition and related dataset definitions. We use it wherever we need it and declare the input or output parameters for a dataset without a by-reference or BIND.

    Will this also be the reason for the memory leak ?

    e.g. Sample.p

    {ttCust.i}

    define output parameter dataset for dscust.

    -

    -

    -

    run CreateData.p(outputDATASET dsCust).

    -

    -

    -

    run UpdateData.p(input-output DATASET dsCust).

    -

    CreateData.p

    {ttCust.i}

    define output parameter dataset for dscust.

    -

    -

    -

    Thanks in advance.

  • Not sure what you're asking now.  Statically defined temp-tables and datasets should not be leaking. If there is a leak there, it would be a bug in the AVM.  But right now, we are not aware of such a bug.  It doesn't matter how you pass them around as parameters.  It is only if you create the TTs or Datasets dynamically that you would be responsible for deleting them and there could be a leak there.

    There's been a lot of information provided in this thread.  I think you need to follow up on one or more of the methods provided and then provide more concrete data as to what you tried and what the results were.  

  • Yes! Just passing static dataset around should not be a / the problem ...

    How do you know that you have a leak on AS? Just a feeling?

    From what you are writing there may be some potential problems:

    - Soap and XML. You parser may leave X-DOC, X-NODEREF ... in memory.

    - Persistent procedures stay in memory...

    How do you pass the datasets to your .Net frontend? C# OpenClient Proxy? Do you call "sample.p" directly from .Net or do you have some kind of "service adapter"?

    To see what's going on the appserver (or even on a client) I use a simple tool.

    - 1) Scan the SESSION on the Appserver and collect objects that stay in memory. Pass the data as a temp-table to the client.

    - 2) Do something like calling your sample.p on the appserver

    - 3) again 1)

    Normally the result of 1) and 3) should show the same objects. If the object list grows then you may have a problem.

    /* MemoryChecker.i/

    DEFINE TEMP-TABLE ttDynObject NO-UNDO

       FIELD ObjectNumber AS INTEGER   LABEL "Number"

       FIELD ObjectHandle AS HANDLE    LABEL "Handle"

       FIELD ObjectType   AS CHARACTER FORMAT "x(32)"  LABEL "Type"

       FIELD ObjectName   AS CHARACTER FORMAT "x(80)"  LABEL "Name"

       INDEX pix IS PRIMARY UNIQUE ObjectNumber.

     

    /* MemoryChecker.p */

    {MemoryChecker.i}

    DEFINE OUTPUT PARAMETER TABLE FOR ttDynObject.

    DEFINE VARIABLE hObject AS HANDLE NO-UNDO.
    DEFINE VARIABLE oObject AS Progress.Lang.Object NO-UNDO.

    DEFINE VARIABLE iSeq AS INTEGER NO-UNDO.

    hObject = SESSION:FIRST-PROCEDURE.
    RUN addWidgets(hObject).
    hObject = SESSION:FIRST-DATASET.
    RUN addWidgets(hObject).
    hObject = SESSION:FIRST-BUFFER.
    RUN addWidgets(hObject).
    hObject = SESSION:FIRST-QUERY.
    RUN addWidgets(hObject).
    hObject = SESSION:FIRST-DATA-SOURCE.
    RUN addWidgets(hObject).
    hObject = SESSION:FIRST-CHILD.
    RUN addWidgets(hObject).
    /*
    hObject = SESSION:FIRST-SERVER.
    RUN addWidgets(hObject).
    */

    oObject = SESSION:FIRST-OBJECT.
    DO WHILE VALID-OBJECT(oObject):
    CREATE ttDynObject.
    ASSIGN iSeq = iSeq + 1
    ttDynObject.ObjectNumber = iSeq
    ttDynObject.ObjectType = oObject:GetClass():TypeName
    ttDynObject.ObjectName = oObject:ToString()
    oObject = oObject:NEXT-SIBLING.
    END.

    PROCEDURE addWidgets:
    DEFINE INPUT PARAMETER phObject AS HANDLE NO-UNDO.

    DO WHILE VALID-HANDLE(hObject):
    CREATE ttDynObject.
    ASSIGN iSeq = iSeq + 1
    ttDynObject.ObjectNumber = iSeq
    ttDynObject.ObjectHandle = hObject
    ttDynObject.ObjectType = hObject:TYPE
    ttDynObject.ObjectName = hObject:NAME.
    hObject = hObject:NEXT-SIBLING.
    END.
    END.

    /* Client prog */

    {MemoryChecker.i}

    RUN MemoryChecker.p ON SERVER <Appserver> (OUTPUT TABLE ttDynObject).

    Then you can load the temp-table into a browse or better a .Net grid with grouping. If you display the number of records of ttDynObject it's easy to see if something goes wrong.

    All of this only makes sense if the client talks to the same appserver agent for every request. 
    - Start the appserver with a single agent (in development).
    - Make the appserver agent stateless bound for the time of checking. (Start a .p o the appserver persistent and delete it when you are done).

    Good luck...

    Thomas