emscripten: Memory leak with std::vector & std::ma

2019-07-22 12:20发布

问题:

I want to know how to properly delete the memory of std::vector & std:: map allocated in c++ code.

I am sharing my code here

 # include <vector>
 # include <stdio.h>
 # include <stdlib.h> //realloc
 # include <math.h>
 # include <map>
 # include <unordered_map>
 #include <emscripten/bind.h>

using namespace emscripten;


struct Edge{
    // Coordinates of two vertices
    float c[6];
    float normal[3];
    int i1,
    i2;
    Edge() {};
    Edge(const float * v1, const float * v2, const float * _normal, int _i1, int _i2) {
        i1 = _i1;
        i2 = _i2;
        memcpy( & normal[0], _normal, 3 * sizeof(float));
        // Compare coordinates lexicographically to select some fixed edge direction
        if (std::lexicographical_compare( & v1[0],  & v1[3],  & v2[0],  & v2[3])) {
            memcpy( & c[0], v1, 3 * sizeof(float));
            memcpy( & c[3], v2, 3 * sizeof(float));
        } else {
            memcpy( & c[0], v2, 3 * sizeof(float));
            memcpy( & c[3], v1, 3 * sizeof(float));
        }
    }

    // Comparison operator for storing edges in std::map
    bool operator < (const Edge & e)const{
        return std::lexicographical_compare( & c[0],  & c[6],  & e.c[0],  & e.c[6]);
    }

    bool operator ==(const Edge & edge)const{

       // return std::lexicographical_compare( & c[0],  & c[6],  & e.c[0],  & e.c[6]);

        if(c[0] == edge.c[0] && c[1] == edge.c[1] && c[2] == edge.c[2] &&
            c[3] == edge.c[3] && c[4] == edge.c[4] && c[5] == edge.c[5]
        )      
            return true;    
        else
            return false;
    }
};

std::vector < float > crossProduct(std::vector < float > vector1, std::vector < float > vector2) {
    std::vector < float > value;
    value.resize(3);
    value[0] = ((vector1[1] * vector2[2]) - (vector1[2] * vector2[1]));
    value[1] = ((vector1[2] * vector2[0]) - (vector1[0] * vector2[2]));
    value[2] = ((vector1[0] * vector2[1]) - (vector1[1] * vector2[0]));
    return value;
}

std::vector < float > subVector(float * vector1, float * vector2) {
    std::vector < float > value;
    value.resize(3);
    value[0] = ((vector1[0]) - (vector2[0]));
    value[1] = ((vector1[1]) - (vector2[1]));
    value[2] = ((vector1[2]) - (vector2[2]));
    return value;
}

std::vector < float > Normalize(std::vector < float > vector) {

    float length = sqrt(pow((vector[0]), 2) + pow((vector[1]), 2) + pow((vector[2]), 2));
    if (length > 0) {
        std::vector < float > value;
        value.resize(3);
        value[0] = vector[0] / length;
        value[1]= vector[1] / length;
        value[2] = vector[2] / length;
        return value;           
    }
    return vector;

}

std::vector<unsigned int> GetFeatureEdges(float fCreaseAngle, uintptr_t input, int nTriangles, bool bBoundaryEdgesOnly){

    std::vector < Edge > edges;
    const float* coords = reinterpret_cast<float*>(input);

    int nEdges = 3 * nTriangles;
    edges.resize(nEdges);
    # pragma omp parallel for
    for (int i = 0; i < nTriangles; i++) {
        int t = 3 * i;
        int y = 3 * 3 * i;
        float p[3][3];
        memcpy( & p[0],  & coords[y], sizeof(float) * 9);
        std::vector < float > normal = crossProduct(subVector(p[1], p[0]), subVector(p[2], p[0]));
        normal = Normalize(normal);
        for (int j = 0; j < 3; j++) {
            int k = (j + 1) % 3;
            edges[i * 3 + j] = Edge( & p[j][0],  & p[k][0],  & normal[0], t + j, t + k);
        }
    }

    float threshold = cos(fCreaseAngle * M_PI / 180);

    std::map < Edge, unsigned char > edge_info;

    for (int i = 0; i < nEdges; i++) {
        std::map < Edge,
        unsigned char > ::iterator it = edge_info.find(edges[i]);
        if (it == edge_info.end())
            edge_info[edges[i]] = 1; // Add edge and mark it as unpaired
        else if (it->second == 1) {
            if (bBoundaryEdgesOnly) {
                edge_info.erase(it);
            } else {
                float dot = edges[i].normal[0] * it->first.normal[0] + edges[i].normal[1] * it->first.normal[1] + edges[i].normal[2] * it->first.normal[2];
                if (dot > 1.0f)
                    dot = 1.0f;
                else if (dot < -1.0f)
                    dot = -1.0f;
                if (dot > threshold) {
                    it->second = 2; // Mark edge as as unpaired, because faces are within crease angle
                    edge_info.erase(it);
                } else
                    it->second = 0; // Mark edge as forced feature edge (this is for case when edge is shared by 3+ faces)
            }
        }
    }

   std::vector<unsigned int> res;
    res.resize(edge_info.size() * 2);
    size_t count=0;
    for (std::map<Edge, unsigned char>::const_iterator it = edge_info.begin(); it != edge_info.end(); it++)
    {       
        res[count++]=it->first.i1;
        res[count++]=it->first.i2;
    }

    edges.clear();
    edge_info.clear();

    return res;
}




EMSCRIPTEN_BINDINGS(VCT_wrappers) {
    register_vector<unsigned int>("VectorUInt");
    function("GetFeatureEdges", &GetFeatureEdges, allow_raw_pointers());
}

emcc compilation is

emcc --bind -o featureEdge.js featureEdge.cpp -O3 --memory-init-file 0 -s ALLOW_MEMORY_GROWTH=1 -v 

and my js function code is

function _arrayToHeap(typedArray) {
        var numBytes = typedArray.length * typedArray.BYTES_PER_ELEMENT;
        var ptr = Module._malloc(numBytes);
        var heapBytes = new Uint8Array(Module.HEAPU8.buffer, ptr, numBytes);
        heapBytes.set(new Uint8Array(typedArray.buffer));
        return heapBytes;
    }
function _freeArray(heapBytes) {
        Module._free(heapBytes.byteOffset);
    }
function GetFeatureEdges_asm(nodeName, fCreaseAngle, vertices, nTriangles, bBoundaryEdgesOnly) {

        //var vertices = new Float32Array([0, 0, 0, 10, 0, 0, 5, 10, 0,
        //          10, 0, 0, 10, 10, 0, 5, 10, 0,
        //          0, 0, 0, 5, 10, 0, 0, 10, 0]);

        //nTriangles = vertices.length / 3 / 3;
        // console.log(nTriangles);

        //var startTime = Date.now();

        var dataHeap1 = _arrayToHeap(vertices);        
        var obj = Module.GetFeatureEdges(35.0, dataHeap1.byteOffset, nTriangles, 0);


        var count = obj.size();

        var indexData = new Uint32Array(count);
        for (var i = 0; i < count; i++)
            indexData[i] = obj.get(i);     


        obj.resize(0, 0);
        obj.delete();


        _freeArray(dataHeap1);

        //var diffTime = Date.now() - startTime;
        //time = time + diffTime

        return indexData;
    }

Here "vertices" is very big array of float values.

If i use this

struct Edge *edges = new struct Edge[nEdges];
delete[] edges;
edges = NULL;

instead of

std::vector < Edge > edges;
edges.resize(nEdges);

there is not memory leak in chrome browser and my emscripten version is 1.37.21.

can any one help me in this?