【问题标题】:Stack overflow when expecting (at most) heap overflow预期(最多)堆溢出时的堆栈溢出
【发布时间】:2013-10-30 10:11:17
【问题描述】:

我在这里遇到了一个对我来说很奇怪的问题,我故意更改了我的程序以使其使用动态内存,因为我之前遇到过堆栈错误。内存密集型部分已更改为动态,但我仍然遇到堆栈溢出,而我预计堆溢出,但我有足够的 RAM,所以即使这些也不应该发生。

头文件:

#ifndef __FPS_h_
#define __FPS_h_

#include "BaseApplication.h"

#include <Ogre/OgreLogManager.h>
#include <Ogre/OgreInstanceManager.h>

#include <btBulletDynamicsCommon.h>
#include <btIDebugDraw.h>

#include "BtOgreExtras.h"
#include "BtOgreGP.h"
#include "btOgrePG.h"

class FPS : public BaseApplication
{
public:
    FPS(void);
    virtual ~FPS(void);

protected:
    virtual void createScene(void);
    virtual void createCamera(void);
    virtual void createViewports(void);

    virtual bool frameRenderingQueued(const Ogre::FrameEvent &evt);

    void initializePhysics(void);
    void initializeGraphics(void);
    void initializeGraphicsBase(void);
    void initializeGraphicsGround(void);
    void initializeGraphicsTiles(void);
    void initializeGraphicsRobot(void);

private:
    Ogre::InstanceManager* tileInstanceManager;
    Ogre::SceneNode*** tileSceneNode[300][300];
    btRigidBody*** tileRigidBody[300][300];
    //Ogre::SceneNode* tileSceneNode;
    //btRigidBody* tileRigidBody;

    Ogre::SceneNode* robotSceneNode;
    btRigidBody* robotRigidBody;

    btDiscreteDynamicsWorld* dynamicsWorld;
    BtOgre::DebugDrawer* debugDrawer;
};

#endif // #ifndef __FPS_h_

部分源文件:

void FPS::initializeGraphicsTiles() {
    //tile instance manager
    uint16_t flags = Ogre::InstanceManagerFlags::IM_USEALL;
    tileInstanceManager = mSceneMgr->createInstanceManager("InstanceManager", "tile.mesh", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::InstanceManager::HWInstancingVTF, 400, flags);

    //fake tile
    Ogre::Entity* entFakeTile = mSceneMgr->createEntity("Tile", "tile.mesh");

    //initialize arrays
    **tileSceneNode = new Ogre::SceneNode**[300];
    **tileRigidBody = new btRigidBody**[300];

    //tile
    for (int x = 0; x <= 300; x++) {
        *tileSceneNode[x] = new Ogre::SceneNode**[300];
        *tileRigidBody[x] = new btRigidBody**[300];
        for (int z = 0; z <= 300; z++) {
            Ogre::InstancedEntity* entTile = tileInstanceManager->createInstancedEntity("Examples/Instancing/VTF/HW/Robot");
            entTile->setCastShadows(true);

            Ogre::SceneNode* tempNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
            tempNode->attachObject(entTile);
            **tileSceneNode[x][z] = tempNode;   

            BtOgre::StaticMeshToShapeConverter converter(entFakeTile);
            btConvexHullShape* mShape = converter.createConvex();
            btScalar mass = 100;
            btVector3 inertia;
            BtOgre::RigidBodyState* state = new BtOgre::RigidBodyState(tempNode);
            btRigidBody* tempBody = new btRigidBody(mass, state, mShape, inertia);

            btTransform originalTransform;
            tempBody->getMotionState()->getWorldTransform(originalTransform);
            btVector3 originalOrigin = originalTransform.getOrigin();
            originalOrigin.setX(originalOrigin.getX() + (x * 10.0));
            originalOrigin.setZ(originalOrigin.getZ() + (z * 10.0));
            originalTransform.setOrigin(originalOrigin);
            tempBody->getMotionState()->setWorldTransform(originalTransform);

            dynamicsWorld->addRigidBody(tempBody);
            **tileRigidBody[x][z] = tempBody;
        }
    }
}

如果我删除(或大幅减少)双数组,那么错误就消失了。

编辑:我知道我还没有清理内存,首先要让应用程序真正运行。

【问题讨论】:

  • 你试过调试器吗?结果如何?
  • @MM。 FPS.exe 中 0x00007FF7AC19C857 处的未处理异常:0xC00000FD:堆栈溢出(参数:0x0000000000000001、0x000000B5ABDC3000)。在它进入主之前。
  • 这不是问题,但是包含两个连续下划线 (__FPS_h_) 的名称和以下划线后跟大写字母的名称保留给实现。不要使用它们。
  • &lt;=300 也是错误的:这将写入 301 个元素...
  • @Roddy 修正了这一点,这实际上是一个很大的错误。它现在给出了一些关于 **tileSceneNode[x][z] = tempNode; 的错误

标签: c++ stack-overflow heap-memory stack-memory


【解决方案1】:

查看sizeof(FPS)。我猜它很大(> 1MB)并且您正在堆栈上分配FPS 本身的实例,对吗?在您使用FPS app; 的地方,将其替换为std::unique_ptr&lt;FPS&gt; app_ptr( new FPS );,应该可以解决您的问题。

【讨论】:

  • main 确实以FPS app; 开头,现在正在尝试获取大小。
  • 我使用std::cout &lt;&lt; "Size: "&lt;&lt; sizeof(FPS);作为主要之后的第一行,但在打印任何内容之前仍然给出了stackoverflow,这正常吗?
  • @skiwi 是的,这是正常的,因为编译器会尝试为FPS app; 保留堆栈空间,即使它随后出现。将其更改为std::unique_ptr&lt;FPS&gt; app_ptr(...),您将看到第一行的输出。
【解决方案2】:

FPS 结构的大小约为 1.4 MiB (sizeof(void *) * 2 * 300 * 300),如果你真的需要指向类指针的二维指针数组,我怀疑不好设计决策。

改用std::vector&lt; std::vector&lt; Ogre::SceneNode &gt; &gt; tileSceneNode;应该会大大减少你的记忆问题

【讨论】:

    【解决方案3】:

    我想你有点困惑。第一行声明了一个 300x300 的指针到指针到指针到 tileRigidBody 的数组。

    btRigidBody*** tileRigidBody[300][300]; 
    

    因此,您有 90,000 个 3* 指针。但是,然后你尝试做这样的事情,假设你有一个指向 300 个指针的指针到 300 个指针......

    **tileRigidBody = new btRigidBody**[300];
    
    for (int x = 0; x <= 300; x++) {
        *tileSceneNode[x] = new Ogre::SceneNode**[300];
        *tileRigidBody[x] = new btRigidBody**[300];
    

    改用std::vector&lt;&gt;,事情会变得清晰很多!

    如果你必须用数组来做(叹气...)然后从这样的开始:-

    btRigidBody** tileRigidBody[300];  // 300 pointers to dynamic arrays 
    

    你的'init'然后看起来像这样(忽略sceneNode的东西,这是相似的):-

    for (int x = 0; x < 300; x++) 
    {
        tileRigidBody[x] = new btRigidBody*[300]; // create array of 300 pointers.
        for (int z = 0; z < 300; z++) 
        {
            ....
            btRigidBody* tempBody = new btRigidBody(mass, state, mShape, inertia);
            tileRigidBody[x][z] = tempBody;
        }
    

    注意 for 循环中的更改为 &lt; 300 - 您的代码溢出了数组。

    警告 - 代码未经测试,但您应该明白。

    【讨论】:

    • 我发现数组更整洁,除了......它们不是。无论如何,你能指出我应该如何处理数组吗?
    猜你喜欢
    • 2019-05-18
    • 2017-07-02
    • 1970-01-01
    • 2012-04-15
    • 2012-12-20
    • 2011-03-02
    • 2011-08-22
    • 2023-03-04
    相关资源
    最近更新 更多