Утечка памяти three.js .dispose() не работает/неправильное использование

Добрый день!

Есть проблема с обработкой памяти. Я прочитал много форумов, но до сих пор не могу найти, что не так с моим кодом.

Я работаю над проектом, в котором я комбинирую d3.js с three.js для визуализации узлов, таких как планеты на космических орбитах. У меня много данных — вроде 8 тысяч планет на 8+ орбитах. Но когда я пытаюсь загрузить новые данные - я не могу уничтожить текущее дерево без утечки памяти.

Буду признателен за любую помощь! Вот часть кода, где я создаю планеты и пытаюсь их уничтожить:

function initTree(root) {
    var start, end;

    var nodes = tree.nodes(root); //this is d3.js tree init
    var depth = getDepth(root);

    var first_x_offset = nodes[0].x;
    if (isNaN(first_x_offset)) {first_x_offset = 0}

    //create orbits
    var orbitTexture = new THREE.ImageUtils.loadTexture('img/orbit_texture.png');
    var orbitMaterial = new THREE.MeshBasicMaterial({map: orbitTexture, transparent:true, side: THREE.DoubleSide, alphaTest: 0.05, opacity:0.3});
    var sphereGeometry = new THREE.SphereGeometry(1, 6, 6);

    var orbitSize = 30;
    for (var k=1; k<depth; k++) {
        var orbit = new THREE.Mesh(new THREE.CircleGeometry(orbitSize*k, 64), orbitMaterial);
        orbit.rotation.x = -90*Math.PI/180;
        orbit.name = 'orbit';
        scene.add(orbit);
    }
    //end orbits

    //camera position
    camera.position.x = 0;
    camera.position.y = 70;
    camera.position.z = -orbitSize*depth-100;

    controls.target.x = 0;
    controls.target.y = 0;
    controls.target.z = 0;

    camera.up.x = 0;
    camera.up.y = 1;
    camera.up.z = 0;

    //this is parent object to place in center
    var parent = new THREE.Object3D();
    parent.name = 'parent';
    scene.add(parent);

    y=0;

    spheres = {};
    objects = [];

    nodes.forEach(function(d) {
        if (d.type == 'BLANK') {return}
        d.x = d.x - first_x_offset;
        if (isNaN(d.x)) {d.x = 0}

        var sphereMaterial = new THREE.MeshLambertMaterial({color: 0xdddddd, wireframe: false, opacity: 0.7, transparent: true});
        var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial );
        sphere.material.color.setHex(color_type[d.type]);

        sphere.castShadow = false; //maybe change to true
        sphere.id2 = y;
        d.id2 = y;
        sphere.d = d;

        sphere.scale.x = radius_type[d.type];
        sphere.scale.y = radius_type[d.type];
        sphere.scale.z = radius_type[d.type];

        sphere.name = 'sphere';

        spheres[y] = sphere;
        //count items of each type
        count_type[d.type]++;
        //how many nodes in tree
        y++;

        //create pivot
        var pivot = new THREE.Object3D;
        //rotate it
        pivot.rotation.y = d.x*Math.PI/180-90;
        //append to parent
        pivot.name = 'pivot';
        parent.add(pivot);
        //add mesh to pivot
        var default_distance = size/(depth-1);
            if (d.y > 0) {
                d.y = (Math.round(d.y/default_distance)) * (orbitSize-8.8);
            }

        sphere.position.x = d.y;
        sphere.position.y = 0; //should be 0!
        sphere.position.z = d.y;

        objects.push(sphere);

        pivot.add(sphere);
    });
    nodesLength = y;

    render();

    $('.loading').fadeOut(500);
    if (!animationId) {
        animate();
    }
    temp = null;
    nodes = null;

}

Итак, я добавляю сферы в родительский Object3D, а затем добавляю их в сцену.

А вот функция уничтожения:

function destroyTree() {
    //spheres
    //console.log(renderer.info);
    var to_delete = [];

    for (var i=0; i<spheres.length; i++) {
        scene.remove(spheres[i]);
        spheres[i].material.dispose();
        spheres[i].geometry.dispose();
    }
    for (var i=0; i<spheres.length; i++) {
        spheres[i] = undefined;
    }
    spheres = {};
    for (var i=0; i<objects.length; i++) {
        scene.remove(objects[i]);
    }
    for (var i=0; i<objects.length; i++) {
        objects[i] = undefined;
    }
    objects = [];

    var parent = scene.getObjectByName('parent');
    scene.remove(parent);

    if (links.length) {
        for (var i=0; i<links.length; i++) {
            scene.remove(links[i]);
        }
    }
    links = [];

    scene.traverse(function (child) {
        if (child instanceof THREE.Mesh) {
            if (child.name.length) {
                to_delete.push(child);
            }
        }

    });

    for (var i=0; i<to_delete.length; i++) {
        scene.remove(to_delete[i]);

            to_delete[i].geometry.dispose();
            to_delete[i].material.dispose();
        to_delete[i] = undefined;
    }

    to_delete = [];

}

person Kaniber    schedule 10.02.2016    source источник


Ответы (1)


Разве при обходе сцены не будут найдены и сферы? И в этом цикле вы можете удалять напрямую без необходимости в массиве to_delete. Если все спецы не являются потомками сцены, то, может быть, стоит подумать, когда их создавать? Это будут просто оптимизации и, вероятно, мало что еще сделают, кроме как выяснить, где может быть утечка.

Тогда, может быть, попробуйте удерживать массив текстур и выпускать их напрямую?

Подождите, вот она, эта ссылка также говорит об удалении объектов и текстур из рендерера.

Утечка памяти в Three.js

renderer.deallocateObject renderer.deallocateTexture

person Master James    schedule 10.02.2016
comment
Спасибо за ваше сообщение. renderer.deallocateObject(сетка); больше не поддерживается. Я понял, что проблема в том, что я помещаю сферы в object3D. Как я вижу, у Three.js проблемы с освобождением памяти из-за этого. - person Kaniber; 11.02.2016