warning C4316: object allocated on the heap may no

2019-02-06 01:49发布

问题:

Important Information:

  • Development OS: Windows 8.1 64 bit
  • Target OS: Windows 8.1 64 bit
  • IDE: Visual Studio 2013 Professional
  • Language: C++

The Problem:

I get the following warning when compiling my static library project through the IDE:

warning C4316: ... : object allocated on the heap may not be aligned 16

I could simply ignore this warning...but I'm assuming it's there for a reason and would like to at least understand what it means and what implications it could have in the future.

I believe this line of code is related to the problem, which is called inside my Win32 window wrapper class:

m_direct3D = new Direct3D(this);

m_direct3D is a pointer to my Direct3D wrapper class.

Here is the header file for the wrapper (I admit it needs trimming down):

#pragma once

// Windows
#include <d3d11.h>
#include <DirectXMath.h>

// Standard
#include <stdint.h>
#include <vector>

// JGlib
#include "Window.h"

namespace JGlib
{
    namespace Graphics
    {
        class Direct3D
        {
        public:
            // Construtor and destructor
            Direct3D(const JGlib::Graphics::Window* window);
            ~Direct3D();

            // Public methods
            void Initialise();
            void BeginDraw();
            void Draw();
            void EndDraw();

        private:
            // Private methods

            // Private member variables
            const Window*               m_window;
            ID3D11Device*               m_device;
            IDXGIAdapter*               m_adapter;
            DXGI_ADAPTER_DESC           m_adapterDescription;
            uint32_t                    m_videoCardMemory;
            IDXGIFactory*               m_factory;
            IDXGIOutput*                m_monitor;
            DXGI_MODE_DESC*             m_displayModes;
            uint32_t                    m_numberOfModes;    
            DXGI_RATIONAL               m_refreshRate;
            DXGI_SWAP_CHAIN_DESC        m_swapChainDescription;
            D3D_FEATURE_LEVEL           m_featureLevel;
            ID3D11DeviceContext*        m_deviceContext;
            IDXGISwapChain*             m_swapChain;
            ID3D11Texture2D*            m_backBuffer;
            ID3D11RenderTargetView*     m_renderTargetView;
            ID3D11Texture2D*            m_depthStencilBuffer;
            D3D11_TEXTURE2D_DESC        m_depthBufferDescription;
            D3D11_DEPTH_STENCIL_DESC    m_depthStencilDescription;
            ID3D11DepthStencilState*    m_depthStencilState;
            ID3D11DepthStencilView*     m_depthStencilView;
            D3D11_RASTERIZER_DESC       m_rasterDescription;
            D3D11_VIEWPORT              m_viewport; 
            float                       m_fieldOfView;
            float                       m_screenAspectRatio;
            ID3D11RasterizerState*      m_rasterState;
            DirectX::XMMATRIX           m_projectionMatrix;
            DirectX::XMMATRIX           m_worldMatrix;
            DirectX::XMMATRIX           m_orthographicMatrix;
            float                       m_screenDepth;
            float                       m_screenNear;
        };
    }
}

I tried googling the issue, but found little information. The information I did find I did not understand.

The conclude, I am asking the following:

  1. What does C4316 mean?
  2. What is causing it in my code?
  3. What implications could this have in the future, if I ignore it?
  4. How do I "fix" the problem that is causing this warning to appear?

Additional Information:

When I changed Visual Studio's configuration manager to compile for x64, this issue does not occur.

回答1:

What does C4316 mean?

C4316 is the error code. It's a unique identifier that makes it easy to find the documentation.

What is causing it in my code?

The usage of the DirectX::XMMATRIX class. Instances of that class must be aligned on 16-byte boundaries. The compiler makes sure that whenever you create a JGLib::Graphics::Direct3D instance on the stack or at global scope, it will align it properly, but if you allocate an instance dynamically on the heap, the compiler can't guarantee that the object will be aligned properly, because malloc() and friends typically only guarantee 8-byte alignment.

What implications could this have in the future, if I ignore it?

Your code may crash when accessing those matrix instances due to SSE instructions operating on misaligned data.

How do I "fix" the problem that is causing this warning to appear?

As the documentation suggests, you need to override your class's operator new and operator delete in order to guarantee 16-byte alignment. You can use _aligned_malloc() and _aligned_free() to allocate and free memory aligned on larger alignments.



回答2:

You need to override the new and delete operators, like this:

__declspec(align(16)) class MyClass
{
    public:
    DirectX::XMMATRIX           m_projectionMatrix;

    virtual ~MyClass()
    {
    }

    void* operator new(size_t i)
    {
        return _mm_malloc(i,16);
    }

    void operator delete(void* p)
    {
        _mm_free(p);
    }
};


回答3:

If you look at the pre-processed code you'll probably find something like this __declspec(align(16)) in there, requesting to be aligned at 16 bytes while new may not align at that constraint. Accoding to http://msdn.microsoft.com/en-us/library/vstudio/dn448573.aspx you can fix it by Override operator new and operator delete for over-aligned types so that they use the aligned allocation routines—for example, _aligned_malloc and _aligned_free.



回答4:

DirectX::XMMATRIX contains SSE data (and is marked with __declspec(align(16)) because of this), and therefore needs to be aligned on 16B boundary, otherwise instructions accessing it will cause access violation.

The warning tells you there is no guarantee memory returned by operator new is 16B aligned.

Can you create the object as a global or local variable instead? That way the compiler can enforce the alignment. If you cannot, you can provide overloaded new and delete for your Direct3D class implemented using _aligned_malloc and _aligned_free.