为什么我得到E_OUTOFMEMORY

Why am I getting E_OUTOFMEMORY?

本文关键字:OUTOFMEMORY 为什么      更新时间:2023-10-16

由于某些原因,下面的代码会给我一个内存不足的错误。我错过了什么?

    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();
    }

只是一个想法,但是你考虑过这个吗?1920 * 1080 * 32bits = 8294400字节现在,8294400字节x 485纹理= 3.836 gb内存。这是32位计算机的极限。我不知道你是在编码32位还是64位程序,但如果是32位,那么你可以处理的最大虚拟内存略低于4GB, 512纹理会超过这个限制。考虑到Release不会立即释放内存,如果实际上是在32位编码,那么应该清楚为什么会耗尽内存。

也许这不是你的情况,但是,例如,微软的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只是包装调用new在一个try-catch(…)块,所以如果Base的构造函数抛出异常失败,任何类型的异常,甚至与内存问题无关,那么p将是NULL,函数将返回E_OUTOFMEMORY

事实证明,catflier在评论中提供了这个问题的答案:

release不会立即释放,因为在代码中没有调用它永远不会这样做。调用devicecontext Flush方法或者某些交换链存在(会冲洗设备)会导致资源删除