NVIDIAGameWorks/PhysX

About memory leaks in GuMeshFactory

Chino66 opened this issue · 3 comments

mConvexMeshes,mTriangleMeshes and mHeightFields in the GuMeshFactory will only release all instance memory when NpFactory::destroyInstance()

But NpFactory::destroyInstance() will only be released when the reference count of the NpPhysics instance is 0, as follows:

// NpPhysics.app:256
PxU32 NpPhysics::releaseInstance()
{
      PX_ASSERT(mRefCount > 0);
      if (--mRefCount) 
            return mRefCount;
      NpFactory::destroyInstance();
      PX_ASSERT(mInstance);
      PX_DELETE_AND_RESET(mInstance);
      Ps::Foundation::decRefCount();
      return mRefCount;
}

It can be seen that even if the ConvexMesh of mConvexMeshes in the code has no reference, it still cannot be released, only the NpPhysics instance is really released.

In our case, we will construct a unique NpPhysics instance for physics logic, and at the same time we will create multiple rooms to load multiple scenes for the player to play, and if the game is over, the scene will be released.
However, although the previously loaded ConvexMesh instance has no reference, it will still be cached in mConvexMeshes. With the passage of server running time, more and more ConvexMesh instances will be accumulated in the loaded scene, resulting in meaningless memory overhead.
PhysX does not provide a method to release part of the ConvexMesh instance.

My solution is to add a method to release the ConvexMesh instance when releasing the scene.

void NpShapeManager::detachAll(NpScene* scene)
{
      // assumes all SQ data has been released, which is currently the responsbility of the owning actor
      const PxU32 nbShapes = getNbShapes();
      NpShape*const *shapes = getShapes();
      if(scene)
            teardownAllSceneQuery(scene->getSceneQueryManagerFast()); 
      // actor cleanup in Scb/Sc will remove any outstanding references corresponding to sim objects, so we don't need to do that here.
      for(PxU32 i=0;i<nbShapes;i++)
      {
            NpShape& shape = *shapes[i];
            if(shape.NpShape::isExclusive())
                  shape.setActor(NULL);
            shape.decRefCount();
      }
      NpFactory::releaseUselessMesh(); // this is my function
      Cm::PtrTableStorageManager &sm = NpFactory::getInstance().getPtrTableStorageManager();
      mShapes.clear(sm);
      mSceneQueryData.clear(sm);
}

When detachAll, I called "NpFactory::releaseUselessMesh()" function

void NpFactory::releaseUselessMesh()
{
      PX_ASSERT(mInstance);
      mInstance->releaseMesh();
}
void NpFactory::releaseMesh()
{
      GuMeshFactory::releaseConvexMesh();
      GuMeshFactory::releaseTriangleMesh();
}
void GuMeshFactory::releaseConvexMesh()
{
      vector<Gu::ConvexMesh*> vector;
      for (int i = 0; i < mConvexMeshes.size(); i++)
      {
            Gu::ConvexMesh* mesh = mConvexMeshes.getEntries()[i];
            if (mesh->getRefCount() == 1)
            {
                  vector.push_back(mesh);
            }
      }
      int vectorCount = 0;
      for (int i = 0; i < vector.size(); i++)
      {
            vector[i]->release();
            vectorCount++;
      }
#ifdef PX_CHECKED
      int cmc = mConvexMeshes.size();
      SSJJ_DEBUGX("GuMeshFactory::releaseConvexMesh ConvexMesh count is %d, vectorCount:%d", cmc, vectorCount);
#endif
}

mTriangleMeshes and mHeightFields are the same case.

It's not clear if this is a memory leak issue?

Are you calling release() on the PxConvexMesh, PxTriangleMesh etc. in your code?

When the meshes are created, they begin with a ref count of 1. They should be released when their ref count hits zero.

When a shape is created referencing a mesh, the ref count on the mesh is incremented. When a shape ceases referencing a mesh, the ref count is decreased.

However, the initial ref count of 1 will remain unless the application also calls release on the mesh. If this gets called before any shapes are attached, the mesh should be immediately released. If the application calls release while a mesh is referenced by a shape, the mesh will be released when the shape ceases to reference the mesh.

Are you calling release() on the PxConvexMesh, PxTriangleMesh etc. in your code?

When the meshes are created, they begin with a ref count of 1. They should be released when their ref count hits zero.

When a shape is created referencing a mesh, the ref count on the mesh is incremented. When a shape ceases referencing a mesh, the ref count is decreased.

However, the initial ref count of 1 will remain unless the application also calls release on the mesh. If this gets called before any shapes are attached, the mesh should be immediately released. If the application calls release while a mesh is referenced by a shape, the mesh will be released when the shape ceases to reference the mesh.

Thanks for your answer, I know what to do, and I found my previous solution was flawed, I should record the meshes loaded by the current scene, and then release them when the scene is released