memory-leaks - 如何正确删除版本 : Box2dWeb-2. 1.a.3、Box2D_v2.3.1r3 中的 box2d 主体? Box2D 错误?

标签 memory-leaks profiling box2d

更新

自从发现问题以来,我还发现用于 Web 的 Box2D 在各个方面都在泄漏:/

为了说明这一点,我制作了一个在静态多边形中移动的简单圆,这是一段时间后的结果。

enter image description here

请注意以下项目是如何泄漏的,因为我没有以任何方式创建任何 body 或改变世界:

  • b2Vec2
  • 特点
  • b2ManifoldPoint
  • b2联系人ID
  • b2歧管
  • b2ContactEdge
  • b2PolyAndCircle联系方式
  • 数组
  • ...

  • 原帖

    我有一个问题,因为我正在分析我的游戏,而垃圾收集器不会删除我的 body 、联系人和其他东西。然后我查看了他们从 GC 中保留了什么以及 Box2D 本身。这可能会导致两种选择:我做得不好或 Box2D 正在泄漏。我认为是我的原因。

    究竟是什么保持它?
  • contact.m_nodeA.other 似乎最常用于防止 GC。
  • 其他时间:m_fixtureB 在联系人中... 查看图片

  • enter image description here
    enter image description here

    你可以看到 body 有一个 __destroyed 属性。这是在使用 world.DestroyBody(body) 删除它之前手动设置的

    当我摧毁一个物体时,我在调用世界上的 step 方法之后调用它。

    正如您从 box2d 方法中看到的那样,它不会摆脱其他变量,也不会将其更改为另一个主体,而我的主体不是 GC。

    知道我在这里缺少什么吗?

    现在只有当 world.Step 没有运行时我才能解决这个问题:
    var gravity = new Box2D.Vec2(0, 0);
    var doSleep = true;
    var world = new Box2D.World(gravity, doSleep);
    var step = false;
    
    var fixtureDef = new Box2D.FixtureDef();
    fixtureDef.density = 1.0;
    fixtureDef.friction = 0.5;
    fixtureDef.restitution = 0.2;
    fixtureDef.shape = new Box2D.PolygonShape();
    fixtureDef.shape.SetAsBox(1, 1);
    var bodyDef = new Box2D.BodyDef;
    bodyDef.type = Box2D.Body.b2_dynamicBody;
    bodyDef.position.x = 0.4;
    bodyDef.position.y = 0.4;
    
    var bodies = []
    var fix = [];
    window.c = function(){
        for(var i = 0; i < 100; i++){
            var body = world.CreateBody(bodyDef);
            body._id = i;
    
            fix.push(body.CreateFixture(fixtureDef));
            bodies.push(body);
    
        }
        if(step){world.Step(1/60, 3, 3); world.ClearForces();}
        console.log('Created', bodies)
        fixtureDef = null;
        bodyDef = null;
    }
    
    window.d = function(){
        _.each(bodies, function(body, i){
            body.DestroyFixture(fix[i]);
            world.DestroyBody(body);
    
            fix[i] = null;
            bodies[i] = null;
        })
        if(step){world.Step(1/60, 3, 3); world.ClearForces();}
        bodies = null;
        fix = null;
    }
    

    把step改成true,内存泄漏问题又出现了。

    重现内存泄漏问题:

    文件中的代码:
    var gravity = new Box2D.Vec2(0, 0);
    var doSleep = true;
    var world = new Box2D.World(gravity, doSleep);
    
    var bodies = []
    window.c = function(){
        for(var i = 0; i < 100; i++){
            var bodyDef = new Box2D.BodyDef();
            bodyDef.type = 2;
    
            var shape = new Box2D.PolygonShape();
            shape.SetAsBox(1, 1);
    
            var fixtureDef   = new Box2D.FixtureDef();
            fixtureDef.shape = shape;
            var body = world.CreateBody(bodyDef);
            body._id = i;
            body.CreateFixture(fixtureDef);
            bodies.push(body);
        }
        world.Step(0.3, 3, 3);
        console.log('Created', bodies)
    }
    window.d = function(){
        _.each(bodies, function(body, i){
            world.DestroyBody(body);
            bodies[i] = null;
        })
        world.Step(0.3, 3, 3);
        bodies = null;
    }
    

    打开谷歌浏览器:
  • 然后打开您的个人资料并制作快照。
  • 现在在控制台中运行 c() 方法以创建 100 个主体
  • 现在快照 2
  • 在快照中搜索 b2Body,您会发现 100 个对象计数
  • 现在运行 d() 删除你所有的 body ;
  • 通过点击垃圾桶强制收集垃圾
  • 制作快照 3
  • 搜索 b2Body,您还会发现 100 个对象计数

  • 在最后一步应该只有 0 个对象,因为它们已被销毁。而不是这个,你会发现这个:
    enter image description here

    现在你可以看到有很多来自 b2ContactEdge 的引用。现在,如果您删除代码的 world.Step 部分,您将只会看到 2 个对主体的引用。

    如果删除此行
    body.CreateFixture(fixtureDef);
    

    或使 body 静止不再泄漏。

    我的游戏循环
    ...gameLoop = function(o){
        // used a lot here
        var world = o.world;
    
        // calculate the new positions
        var worldStepSeconds = o.worldStepMs / 1000;
    
        // step world
        world.Step(worldStepSeconds, o.velocityIterations, o.positionIterations)
    
        // render debug
        if(o.renderDebug){
            world.DrawDebugData();
        }
    
        // always to not accumulate forces, maybe some bug occurs
        world.ClearForces();
    
        // tick all ticking entities
        _.each(o.getTickEntitiesFn(), function(actor){
            if(!actor) return;
            actor.tick(o.worldStepMs, o.lastFrameMs);
        })
    
    
        // update PIXI entities
        var body = world.GetBodyList();
        var worldScale = world.SCALE;
        var destroyBody = world.DestroyBody.bind(world);
        while(body){
            var actor = null;
            var visualEntity = null;
            var box2DEntity = o.getBox2DEntityByIdFn(body.GetUserData());
            if(box2DEntity){
                visualEntity = o.getVisualEntityByIdFn(box2DEntity.getVisualEntityId());
                if(box2DEntity.isDestroying()){
                    // optimization
                    body.__destroyed = true;
                    world.DestroyBody(body);
                    box2DEntity.completeDestroy();
                }
            }
            if(visualEntity){
                if(visualEntity.isDestroying()){
                    visualEntity.completeDestroy();
                }else{
                    var inverseY = true;
                    var bodyDetails = Utils.getScreenPositionAndRotationOfBody(world, body, inverseY);
                    visualEntity.updateSprite(bodyDetails.x, bodyDetails.y, bodyDetails.rotation);
                }
            }
            // this delegates out functionality for each body processed
            if(o.triggersFn.eachBody) o.triggersFn.eachBody(world, body, visualEntity);
    
            body = body.GetNext();
        }
    
        // when a joint is created is then also created it's visual counterpart and then set to userData.
        var joint = world.GetJointList();
        while(joint){
            var pixiGraphics = joint.GetUserData();
            if(pixiGraphics){
                // In order to draw a distance joint we need to know the start and end positions.
                // The joint saves the global (yes) anchor positions for each body.
                // After that we need to scale to our screen and invert y axis.
                var anchorA           = joint.GetAnchorA();
                var anchorB           = joint.GetAnchorB();
                var screenPositionA = anchorA.Copy();
                var screenPositionB = anchorB.Copy();
                // scale
                screenPositionA.Multiply(world.SCALE);
                screenPositionB.Multiply(world.SCALE);
                // invert y
                screenPositionA.y = world.CANVAS_HEIGHT - screenPositionA.y
                screenPositionB.y = world.CANVAS_HEIGHT - screenPositionB.y
    
                // draw a black line
                pixiGraphics.clear();
                pixiGraphics.lineStyle(1, 0x000000, 0.7);
                pixiGraphics.moveTo(screenPositionA.x, screenPositionA.y);
                pixiGraphics.lineTo(screenPositionB.x, screenPositionB.y);
            }
            joint = joint.GetNext();
        }
    
        // render the PIXI scene
        if(o.renderPixi){
            o.renderer.render(o.stage)
        }
    
        // render next frame
        requestAnimFrame(o.requestAnimFrameFn);
    }
    

    来自 Box2d 的代码:
    b2ContactManager.prototype.Destroy = function (c) {
    var fixtureA = c.GetFixtureA();
    var fixtureB = c.GetFixtureB();
    var bodyA = fixtureA.GetBody();
    var bodyB = fixtureB.GetBody();
    if (c.IsTouching()) {
    this.m_contactListener.EndContact(c);
    }
    if (c.m_prev) {
    c.m_prev.m_next = c.m_next;
    }
    if (c.m_next) {
    c.m_next.m_prev = c.m_prev;
    }
    if (c == this.m_world.m_contactList) {
    this.m_world.m_contactList = c.m_next;
    }
    if (c.m_nodeA.prev) {
    c.m_nodeA.prev.next = c.m_nodeA.next;
    }
    if (c.m_nodeA.next) {
    c.m_nodeA.next.prev = c.m_nodeA.prev;
    }
    if (c.m_nodeA == bodyA.m_contactList) {
    bodyA.m_contactList = c.m_nodeA.next;
    }
    if (c.m_nodeB.prev) {
    c.m_nodeB.prev.next = c.m_nodeB.next;
    }
    if (c.m_nodeB.next) {
    c.m_nodeB.next.prev = c.m_nodeB.prev;
    }
    if (c.m_nodeB == bodyB.m_contactList) {
    bodyB.m_contactList = c.m_nodeB.next;
    }
    this.m_contactFactory.Destroy(c);
    --this.m_contactCount;
    }
    
    
    b2ContactFactory.prototype.Destroy = function (contact) {
        if (contact.m_manifold.m_pointCount > 0) {
            contact.m_fixtureA.m_body.SetAwake(true);
            contact.m_fixtureB.m_body.SetAwake(true);
        }
        var type1 = parseInt(contact.m_fixtureA.GetType());
        var type2 = parseInt(contact.m_fixtureB.GetType());
        var reg = this.m_registers[type1][type2];
        if (true) {
            reg.poolCount++;
            contact.m_next = reg.pool;
            reg.pool = contact;
        }
        var destroyFcn = reg.destroyFcn;
        destroyFcn(contact, this.m_allocator);
    }
    

    最佳答案

    我有同样的问题,但我想我是从哪里找出来的。

    代替 m_* 尝试函数,例如 GetFixtureA()而不是 m_fixtureA .

    关于memory-leaks - 如何正确删除版本 : Box2dWeb-2. 1.a.3、Box2D_v2.3.1r3 中的 box2d 主体? Box2D 错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20817760/

    相关文章:

    c# - 模拟 IDisposable 类

    java - 弱引用而不是 getActivity()(Android 避免内存泄漏)?

    ios - 带有自定义多边形的box2d崩溃

    python - PyBox2D - NoneType 在碰撞过滤期间不可下标

    c# - C# WPF 中的内存泄漏

    valgrind 的 c 快速排序内存泄漏

    visual-studio - 当我在 Azure 中运行 Visual Studio 探查器时未找到符号

    python - 为什么 Python 中的连接看起来越来越慢?

    java - 如何分析和理解 Java Web 应用程序的输出

    objective-c - Xcode:Cocos2d:无法使用 Box2D 创建世界