【问题标题】:Memory usage going up. Memory released is not being reused内存使用率上升。释放的内存没有被重用
【发布时间】:2012-07-26 00:36:37
【问题描述】:

我正在使用debug_new 来查找内存泄漏。我正在删除我的对象,并且 debug_new 没有显示我泄漏它们的任何痕迹。

我已经阅读了几个关于内存碎片的主题。但我还是很困惑。此时我正在测试我的框架并且我正在做一个简单的测试。我像这样创建一个新对象:

if(sf::Keyboard::isKeyPressed(sf::Keyboard::Space)){
    artemis::Entity& e = world->createEntity();
    e.addComponent(new PositionComponent(posX,posY));
    e.addComponent(new MovementComponent(500,0));
    e.addComponent(new SpriteComponent(TextureManager::getInstance().getTexture("bullet.png")));
    e.addComponent(new ColliderComponent(10,10));
    e.refresh();
    e.setGroup("BULLET");
}

这些“组件”在名为“EntityManager”的管理器中进行管理,该管理器重用实体对象,但在将实体发送回“池”时销毁组件。 我已经对此进行了测试,如果池中没有可用的实体,则只会创建新实体。

从上面的代码可以看出。在这个简单的测试中,模式是相同的。然而,分配器继续使用新内存,而不是重用任何以前使用过的内存。每个空格键命中(每帧 1/60)创建几千个使我的记忆进入 2 gig 频谱。组件甚至没有那么大。例如:

class ColliderComponent : public artemis::Component{

    public:
    int width,height,collidionsId;

    ColliderComponent(int width, int height){
        this->width = width;
        this->height = height;
    }
};

到目前为止,大多数组件都是简单的整数“集合”。它们非常轻巧。它绝对应该重用一些以前分配/释放的内存。但事实并非如此。

也许我错过了什么。有没有人对可能发生的事情有不同的想法?有没有好的(免费)内存分析器? 如果不是因为我的组件,那么缺陷一定在其他地方。我现在根本看不到它,至少可以说令人沮丧。

编辑: 看起来我忽略了导致重大泄漏的不同部分。这显然是我自己的一个愚蠢的错误。

这是罪魁祸首: e.setGroup("BULLET");

"BULLET" 被保存为一个指针(我应该重新设计它)并且覆盖指向实体 id 索引处现有字符串的指针。我不知道为什么我忽略了这一点,但我的内存分配现在稳定了!

我本可以使用智能指针,但到目前为止我已经从中学到了很多东西!感觉自己有所成就了=D

【问题讨论】:

  • 你如何衡量使用的内存?
  • 这听起来可能很傻。但我只是检查任务管理器。但即便如此,这个简单的应用程序也不应该超过 1 gig。不在当前状态。
  • 这是使用哑指针不明智的原因之一。
  • Memoryram 是这个问题的选择非常糟糕的标签。更好的将与您使用的编程语言和操作系统有关,因此您会引起一些熟悉的人的注意。选择合适的标签会有所帮助,因为您会更快地得到答案(此外还会在此过程中浪费更少的人的时间)。如果你能适当地编辑它们会很有帮助。
  • 对于e.addComponent(new ColliderComponent(10,10)),对应的销毁在哪里? new 是否为所有组件重载以从 EntityManager 获取内存?

标签: c++ windows memory-management memory-leaks


【解决方案1】:

我在ColliderComponent 中没有看到重载的new 运算符,这让我相信您总是从堆中分配内存,并将内存分配给您的EntityManager。这肯定看起来像一个泄漏,一旦你的EntityManager 被破坏,它就会消失。

编辑:我现在更了解您的代码是如何工作的。您的EntityManager 不会缓存组件,只有Entity 会缓存。

【讨论】:

  • 那么你有什么建议呢?因为我在这里真的很茫然。
  • @Sidar:您如何想象 Entity 对象会在 EntityManager 中被重用?是否有从池中拉出组件的接口?
  • @Sidar:artemis::Component 有虚拟析构函数吗?
  • 确实如此。它实际上是一个纯虚拟析构函数。对于多态性。但它几乎是空的。除了提供带有纯虚析构函数的基类之外,Component 中没有任何实际意义。
  • 您的删除组件代码对我来说有点混乱。您确定实体的所有组件都被该代码删除了吗?
【解决方案2】:

您说您正在使用任务管理器来评估内存消耗 - 大多数内存管理器不会立即将释放的内存返回给操作系统(这是一个相当昂贵的操作),而是保持内存可供应用程序本身使用。因此,您的应用程序的内存管理器(它是 C++ 运行时的一部分)会将您释放的块标记为空闲,并且能够在以后有另一个内存请求时重用它。

这具有性能优势,因为运行时的内存管理器不必经常调用操作系统来释放然后重新获取内存。

【讨论】:

  • 我明白这一点。然而。看起来内存从未被重用。它超过了 2gig 标记并继续前进。本示例不应发生这种情况。我见过“更重”的程序甚至没有超过 500mb。
猜你喜欢
  • 1970-01-01
  • 2011-05-16
  • 2018-08-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多