为什么我的程序会出现E_OUTOFMEMORY错误?

4
由于某些原因,下面的代码会导致内存溢出错误。我错过了什么吗?
    for(int n = 0; n < 512; ++n)
    {               
        D3D11_TEXTURE2D_DESC texture_desc = {};
        texture_desc.Width                = 1920;
        texture_desc.Height               = 1080;
        texture_desc.MipLevels            = 1;
        texture_desc.ArraySize            = 1;
        texture_desc.Format               = DXGI_FORMAT_R8G8B8A8_UNORM;
        texture_desc.SampleDesc.Count     = 1;
        texture_desc.Usage                = D3D11_USAGE_DEFAULT;
        texture_desc.BindFlags            = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;

        ID3D11Texture2D* target_d3d_ptr;
        HRESULT hr = this->device_ptr->CreateTexture2D(&texture_desc, nullptr, &target_d3d_ptr);
        if(FAILED(hr))
            throw runtime_error(_com_error(hr).ErrorMessage());

        target_d3d_ptr->Release();
    }

1
当出现 E_OUTOFMEMORY 错误时,当前的 n 是多少? - Sergei Nikulov
1
假设这是GPU内存,那么是的,它将没有用处。我不是这个领域的专家,所以我不知道GPU是否有类似的东西存在,但我怀疑在这里调用 Release() 不会立即释放内存,可能只是将其标记为“待释放”。但再次强调,我可能在说一些愚蠢的话——只是根据推断工作而已。 - Andy Prowl
2
@AndyProwl,你说得对,release并不会立即释放资源,因为代码中没有调用,所以它永远不会释放。调用设备上下文Flush方法或一些交换链呈现(这将刷新设备)将导致资源删除。 - mrvux
1
@ronag - 如果上面的评论解决了您的问题,请请求解决问题的人将其建议输入为答案,然后请选择该答案。如果您自己解决了问题,请提供一个答案,然后选择它。这将使您的问题不再出现在“未回答的问题”选项卡中。否则,请删除您的问题,以便它不会出现在“未回答的问题”中。 - phonetagger
1
@ronag - 没错。但是,除非您删除问题或选择答案,否则您的问题将永远显示在“未回答的问题”选项卡中。为什么不要求catfliers将他的建议作为答案提交,这样catfliers就可以因回答您的问题而获得“报酬”? - phonetagger
显示剩余9条评论
3个回答

2
也许这不是你的情况,但例如,微软的COM方法CComObject::CreateInstance可能会返回E_OUTOFMEMORY(至少在我所在环境中的实现,即Visual Studio 2012),我认为这可能会误导人。
COM方法类似于以下内容(在atlcom.h中):
ATLPREFAST_SUPPRESS(6387)
template <class Base>
_Success_(return == S_OK) HRESULT WINAPI CComObject<Base>::CreateInstance(
    _Deref_out_ CComObject<Base>** pp) throw()
{
    // code omitted

    HRESULT hRes = E_OUTOFMEMORY;
    CComObject<Base>* p = NULL;
    ATLTRY(p = new CComObject<Base>())
    if (p != NULL)
    {
        // code omitted
    }
    *pp = p;    
    return hRes;
}
ATLPREFAST_UNSUPPRESS()

我觉得上述代码即使你有很多可用内存,也可能返回E_OUTOFMEMORY:宏ATLTRY只是在try-catch(...)块中包装了对new的调用,因此如果Base的构造函数失败并抛出异常,任何类型的异常,即使与内存问题无关,p将为NULL,并且该函数将返回E_OUTOFMEMORY


问题在评论中得到了解答。事实证明,GPU上的内存没有立即被释放。需要执行一些刷新命令缓冲区的操作,以通知GPU纹理不再使用。 - Ross Ridge

2
只是一个想法,但你是否考虑过这个:1920 * 1080 * 32位 = 8294400字节。现在,8294400字节x 485个纹理= 3.836 GBytes的内存。这已经接近32位机器的极限了。我不知道你是否编写32位或64位程序,但如果是32位,则可以寻址的最大虚拟内存略低于4GB,而512个纹理则超出了此限制。考虑到Release不会立即释放这个内存,如果你实际上是在32位环境下编码,那么你为什么会用尽内存就很清楚了。

2
原来,catflier在评论中提供了这个问题的答案:
释放并不会立即释放,因为在代码上没有调用,所以它永远不会这样做。调用设备上下文的Flush方法或一些交换链呈现(将刷新设备)将导致资源删除。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接