Search code examples
c++memory-leaksassimp

Assimp leaking memory


I recently passed my game engine to a memory leak test with valgrind; it actually told me that there are ~7000 bytes being leaked in my Mesh class; the strange thing is that is tells me this :

7,280 bytes in 1 blocks are definitely lost in loss record 391 of 393
==5639==    at 0x4C2C100: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5639==    by 0x598647E: ??? (in /usr/lib/libassimp.so.3.0.1264)
==5639==    by 0x597F37D: ??? (in /usr/lib/libassimp.so.3.0.1264)
==5639==    by 0x58139E5: ??? (in /usr/lib/libassimp.so.3.0.1264)
==5639==    by 0x581E2B2: Assimp::Importer::ReadFile(char const*, unsigned int) (in /usr/lib/libassimp.so.3.0.1264)
==5639==    by 0x40D71A: glDetail::CMesh::CMesh(char const*) (Mesh.cpp:49)
==5639==    by 0x412FB5: _ZN9__gnu_cxx13new_allocatorIN8glDetail5CMeshEE9constructIS2_IRPKcEEEvPT_DpOT0_ (in /home/mattmatt/workspace/C++/alpha++/main-dev/eclipse/Alpha++/Debug/Alpha++)

So Question is : is Assimp responsible for the leaked memory ? Here is the part of code which is in question :

CMesh::CMesh(const char* fileName){
    Assimp::Importer importer;

    const aiScene* scene = importer.ReadFile(fileName,  aiProcess_Triangulate |
                                                        aiProcess_GenSmoothNormals |
                                                        aiProcess_FlipUVs |
                                                        aiProcess_CalcTangentSpace
                                                        );
    if(!scene){
        LOG_ERROR("Mesh", "ERROR LOADING MESH ! : CHECK THE SUPPORTED MODEL TYPES MODEL I OR THE FILE PATH !");
        abort();
    }
    const aiMesh* model = scene->mMeshes[0];

    std::vector<Vertex> vertices;
    std::vector<unsigned int> indices;

    const aiVector3D aiZeroVector(.0f, .0f, .0f);
    IndexedModel out;

    for(unsigned i = 0; i < model->mNumVertices; ++i)
    {
        const aiVector3D* pPos = &(model->mVertices[i]);
        const aiVector3D* pNormal = &(model->mNormals[i]);
        const aiVector3D* pTexCoord = model->HasTextureCoords(0) ? &(model->mTextureCoords[0][i]) : &aiZeroVector;

        const aiVector3D* pTangent = &(model->mTangents[i]);

        Vertex vert (
                        glm::vec3(pPos->x, pPos->y, pPos->z),///positions
                        glm::vec2(pTexCoord->x, pTexCoord->y),///UV coords
                        glm::vec3(pNormal->x, pNormal->y, pNormal->z),///normals
                        glm::vec3(pTangent->x, pTangent->y, pTangent->z)///tangents

                    );

        vertices.push_back(vert);

        out.positions.push_back(*vert.getPos());
        out.texCoords.push_back(*vert.getTexCoord());
        out.normals.push_back(*vert.getNormal());
        out.tangents.push_back(*vert.getTangent());
    }
    for(unsigned i = 0; i < model->mNumFaces; ++i){
        const aiFace& face = model->mFaces[i];
        assert(face.mNumIndices == 3);
        indices.push_back(face.mIndices[0]);
        indices.push_back(face.mIndices[1]);
        indices.push_back(face.mIndices[2]);
    }


    importer.FreeScene();

    out.indices = indices;
    initMesh(out);
}

the full code for my mesh class can be viewed at this question Memory Leak in opengl Mesh class if necessary :)

////////////////////////////Important Edit///////////////////////////

I isolated the part of code which leaked resources :

Assimp::Importer importer;

       const aiScene* scene = importer.ReadFile("res/Suzy.obj",  aiProcess_Triangulate |
                                                           aiProcess_GenSmoothNormals |
                                                           aiProcess_FlipUVs |
                                                            aiProcess_CalcTangentSpace
                                                           );
       if(!scene){
           LOG_ERROR("Mesh", "ERROR LOADING MESH ! : CHECK THE SUPPORTED MODEL TYPES MODEL I OR THE FILE PATH !");
           abort();
       }

What do I have to change ?


Solution

  • The documentation of Importer::ReadFile(const char *, unsigned) states:

    If the call succeeds, the contents of the file are returned as a pointer to an aiScene object. The returned data is intended to be read-only, the importer object keeps ownership of the data and will destroy it upon destruction.

    Based on this, it would appear that you are using the Assimp library correctly, but there is a memory leak issue within the library itself.

    The ??? lines mean that debugging information is not available. If this is indeed a true memory leak, it is immensely useful to have debugging information in order to determine exactly where the memory leak is occurring. Debugging information is especially important in this case because Importer::ReadFile() calls a non-virtual BaseImporter::ReadFile(const Importer*, const std::string&, IOSystem*) member, which then calls the pure-virtual BaseImporter::InternReadFile(const std::string&, aiScene*, IOSystem*) member. I would assume that 0x58139E5 is BaseImporter::ReadFile(). Stack frames beyond that would depend on which BaseImporter implementation was selected by Importer::ReadFile().

    On Fedora systems, debugging information can be obtained by installing the corresponding debuginfo package when available. Fedora provides an assimp-debuginfo package that can be installed via:

    sudo yum --enablerepo fedora-debuginfo,updates-debuginfo install assimp-debuginfo
    

    On Ubuntu and Debian systems, debugging information is obtained by installing the -dbg package when available. Unfortunately, neither Debian 8 'Jessie' nor Ubuntu 15.04 'Vivid Vervet' offer a libassimp-dbg package.

    You can try building Assimp from source with debugging information. See the Stack Overflow question Creating symbol table for gdb using cmake for instructions on how to do this.