Three.js r88 - 内存泄漏

时间:2017-11-08 20:33:13

标签: javascript three.js

前进:我已经查看了我能找到的每三个.js内存泄漏帖子,其中大部分内容已经过时,已弃用功能。即使是较新的也不会在这种情况下产生任何结果。

客户端框架:React v15.5.4,ThreeJS r88。

以下是JS Heap的性能简介:

enter image description here

渲染循环期间一切正常。在我更改组件并在组件componentWillUnmount生命周期方法中触发清理功能后,我希望蓝色的JS Heap行位于底部。不幸的是,这种情况并非如此。蓝线变平的地方是组件发生变化并执行清理代码的地方。不知怎的,堆增加???

以下是将对象添加到场景和清理/处理机制的代码:

/*
* This is how the models are added to the scene. A listener is added to each object in the scene
* to invoke Builder.prototype.model._dispose when the remove event is triggered
*/
//..
init: {
    // ...
    _modelInScene: function( modelData ) {
        const { dimensions, index, model, sectionModelsArray, tableConfig, type } = modelData;

        sectionModelsArray.push( model );

        // size and position model
        //Builder.model._sizeAndPosition( { model, dimensions, type, index }, tableConfig );

        // add model to scene
        _threejs.scene.add( model );

        model.addEventListener( "removed", Builder.prototype.model._dispose );

        // store type of model on model meshes so that we can get this information during raycasting
        model.traverse( function ( child ) {
            child.addEventListener( "removed", Builder.prototype.model._dispose );

            if ( child instanceof THREE.Mesh ) {
                child._modelType = type;
            }
        } );
    },
    // ...
},
//..
/*
* This is the function triggered in componentWillUnmount method of the react component that contains
* the three js scene. In this function I remove all top level children from the scene. This triggers
* the listeners for the remove event and calls the dispose function which releases geometry, materials,
* and removes nested objects from scene triggering their remove events etc...
*/
//...
cleanup: function() {
    // dispose of scene listeners
    Builder.prototype._removeListeners();

    // TODO - implement cache

    // clear the model cache
    //Builder.prototype.model._clearCache();

    // clear the texture cache
    //Builder.prototype.texture._clearCache();

    // remove tableConfig from _threejs object
    _tableConfig = null;

    // reset tableConfig in redux store
    _dispatch( removeTable() );

    // remove all children from scene
    while( _threejs.scene.children.length > 0 ) {
        _threejs.scene.remove( _threejs.scene.children[ 0 ] );
    }

    // remove reference to animations in the heightAnimationController
    if ( _threejs.heightAnimationController ) _threejs.heightAnimationController.dispose();

    // reset _shouldCastRay to false
    _shouldCastRay = false;

    // dispose of controls listeners
    _threejs.controls.dispose();

    // dispose of rendering context
    _threejs.renderer.dispose();

    // reset _threejs object
    _threejs = {
        camera: null,
        controls: null,
        heightAnimationController: null,
        lookAt: null,
        mouseCoords: null,
        raycaster: null,
        raycasterTargetModels: [],
        renderer: null,
        scene: null,
        sceneHeight: 0,
        sceneWidth: 0,
        tableConfig: null
    };

    // cancel requestAnimationFrame from Builder.prototype._animate3js
    cancelAnimationFrame( _animationFrameId );
},
//...

/*
* Dispose function invoked by remove listeners
*/
//...
model: {
    //..
    _dispose: function() {
        const target = arguments[ 0 ].target;

        if ( target instanceof THREE.Mesh ) {
            if ( target.geometry ) {
                target.geometry.dispose();
            }

            if ( target.material ) {
                if ( target.material.bumpMap ) target.material.bumpMap.dispose();
                if ( target.material.envMap ) target.material.envMap.dispose();
                if ( target.material.lightMap ) target.material.lightMap.dispose();
                if ( target.material.map ) target.material.map.dispose();
                if ( target.material.normalMap ) target.material.normalMap.dispose();
                if ( target.material.specularMap ) target.material.specularMap.dispose();

                target.material.dispose();
            }
        } else {
            while ( target.children.length > 0 ) {
                target.remove( target.children[ 0 ] );
            }
        }
    },
    //..
},
//..

在清理过程中,我处理了OrbitControls,WebGLRenderingContext,所有Textures和Geometries,并删除了所有与three.js相关的引用。

此外,我要更改的反应组件只是一个空div元素。这个无状态组件中没有任何东西可以解释堆中的跳转。

我花了很多时间查看three.js源代码,在stackoverflow上,以及其他试图解决这个问题的网站。非常感谢任何帮助!

编辑:添加到场景中的“模型”是THREE.Scene的实例,并包含其中包含网格的Object3D容器。它们从混合器导出并通过THREE.ObjectLoader加载。以防万一是相关的。

编辑#2:经过对查找和修复内存泄漏的更多研究后,我有更好的时间表来显示。这在开始时有一个强制垃圾收集,堆在13,522,544。大峰值是三个js场景的初始化和模型的加载。那部分是预料之中的。离开应用程序的三个js部分后,运行处理代码,然后强制进行另一次垃圾回收。在第二次垃圾收集之后,我希望堆与开头的堆相同。我在app中的同一个地方并且所有三个j都应该被清理掉了,但堆现在是14,830,808;增加1,308,264。

以下是时间表:

enter image description here

我可以提供任何要求的信息,目前是纺车:(

编辑#3:

我已经将每次初始化和解构模型的泄漏减少到大约100kb。不幸的是,快照之间的比较在我看来是相当模糊的。 (虽然我不熟悉泄漏!)

enter image description here

看起来一切都回归到THREE或webpackJsonp。有什么建议吗?我想如果我想使用库,这可能是我必须要忍受的。

0 个答案:

没有答案