Opened 6 years ago

Closed 6 years ago

#5406 closed defect (fixed)

Memory Leak in memory_pool

Reported by: schmitz.basti@… Owned by: Lennart Ochel
Priority: high Milestone: Future
Component: Run-time Version: v1.14.0-dev-nightly
Keywords: Cc:

Description

The following model leaks memory every time the function fmi2GetReal is called:

model LeakyModel
  parameter Integer arraySize = 150;
  input Real[arraySize] inputArray;
  output Real[arraySize] outputArray;
equation
  outputArray = functions.leakyCopy(arraySize, inputArray);
end LeakyModel;

package functions
  function leakyCopy
    input Integer s;
    input Real[s] arrayToCopy;
    output Real[s] copiedArray;
    algorithm
    copiedArray := arrayToCopy;
  end leakyCopy;
end functions;

How to reproduce:
System: Ubuntu Linux 18.04 LTS
OpenModelica version: 1.13.2 and current dev (OMCompiler v1.14.0-dev.177+gb70342a5e) both show the same behavior

Build FMU via oms script:

loadModel(Modelica);getErrorString();
loadFiles(fileNames={"LeakyModel.mo"});getErrorString();
buildModelFMU(LeakyModel, platforms={"static"}, includeResources=true); getErrorString();

I used FMI4cpp to load the FMU and call fmi2SetReal and fmi2GetReal in a loop, like this:

int main() {
    fmi2Fmu fmu("../resources/LeakyModel.fmu");
    auto me_fmu = fmu.asModelExchangeFmu();
    auto md = me_fmu->getModelDescription();

    logger::info("Name={}, start={}", var.name(), var.start().value_or(0));

    auto slave = me_fmu->newInstance();
    logger::info("modelIdentifier={}", slave->getModelDescription()->modelIdentifier);

    slave->enterInitializationMode();
    slave->exitInitializationMode();

    fmi4cpp::fmi4cppInteger arraySize;
    slave->readInteger(md->getVariableByName("arraySize").valueReference, arraySize);

    logger::info("The array is of size " + std::to_string(arraySize));

    auto inReference = md->getVariableByName("inputArray[1]").valueReference;
    auto outReference = md->getVariableByName("outputArray[1]").valueReference;

    fmi4cpp::fmi4cppReal r;
    for(int i = 0; i < 1000000; ++i){
        slave->writeReal(inReference, i);
        slave->readReal(outReference, r);
      logger::info("Read: " + std::to_string(r));
      std::this_thread::sleep_for(10ms);
    }

    return 0;
}

(The leak is small, but this model is just a trimmed down version to showcase the faulty behavior a bigger one I am using shows)

The valgrind output looks like this:

==26715== 62,914,560 bytes in 4 blocks are still reachable in loss record 148 of 148
==26715==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==26715==    by 0x7901C7E: pool_expand (memory_pool.c:103)
==26715==    by 0x7901C7E: pool_malloc (memory_pool.c:113)
==26715==    by 0x7905480: alloc_real_array (real_array.c:85)
==26715==    by 0x78315CD: omc_functions_leakyCopy (in /tmp/fmi4cpp_LeakyModel_17449512/binaries/linux64/LeakyModel.so)
==26715==    by 0x7831375: LeakyModel_eqFunction_2 (in /tmp/fmi4cpp_LeakyModel_17449512/binaries/linux64/LeakyModel.so)
==26715==    by 0x78318D1: LeakyModel_functionAlgebraics (in /tmp/fmi4cpp_LeakyModel_17449512/binaries/linux64/LeakyModel.so)
==26715==    by 0x78131F1: fmi2GetReal (in /tmp/fmi4cpp_LeakyModel_17449512/binaries/linux64/LeakyModel.so)
==26715==    by 0x150DF8: fmi4cpp::fmi2::fmi2Library::readReal(void*, unsigned int, double&) (fmi2Library.cpp:199)
==26715==    by 0x156DDC: fmi4cpp::AbstractFmuInstance<fmi4cpp::fmi2::fmi2ModelExchangeLibrary, fmi4cpp::fmi2::ModelExchangeModelDescription>::readReal(unsigned int, double&) (AbstractFmuInstance.hpp:145)
==26715==    by 0x11C803: main (fmu_test.cpp:75)

The memory pool just keeps getting bigger and bigger and I see no way to let the FMU clean up.

Am I doing something fundamentally wrong or is this a bad memory leak?

Change History (6)

comment:1 by Martin Sjölund, 6 years ago

Well, we should be able to call omc_alloc_interface.collect_a_little, which has a weird name but actually free's the pool. There is just one problem: if you instantiate multiple copies of the same FMU the global variable for the string pool will clear both of them (or if you have multiple OpenModelica FMUs and do a shallow loading of the shared objects).

For regular simulations this is called once for every step.

@lochel: do you know where it would be (sort of) safe to add these calls in the exported FMU?

comment:2 by schmitz.basti@…, 6 years ago

Any news on this? If you can provide me with some pointers I might be able to come up with a solution myself and create a PR.

comment:3 by Martin Sjölund, 6 years ago

You can try the latest nightly builds and see if it works any better. There are a few changes in there.

comment:4 by schmitz.basti@…, 6 years ago

Thank you very much, that did it :)

comment:5 by Francesco Casella, 6 years ago

@schmitz.basti, if the issue is solved for you, please close the ticket :)

comment:6 by schmitz.basti@…, 6 years ago

Resolution: fixed
Status: newclosed

Done!

Note: See TracTickets for help on using tickets.