Ошибка отладочного подтверждения ... _BLOCK_TYPE_IS_VALID (pHead-> nBlockUse) - PullRequest
16 голосов
/ 02 декабря 2011

У меня действительно плохая утечка памяти, которую я пытаюсь исправить, но каким-то образом я не могу удалить Объекты, не запустив эту диссертацию.

Я искал решение через Google и прочитал Вопросыв stackoverflow об этой ошибке, но я все еще не смог найти ответ!

Возможные причины для получения этой ошибки в соответствии с моими исследованиями:
1. удаление объектов более чем на один
2. теневое копирование
3. Создание и удаление объектов, загруженных из внешней библиотеки DLL
4. Создание объектов без сохранения указателя

НО:
1. Я проверил код и не смог найтидвойное удаление
2. Я использую конструктор копирования для копирования объектов
3. Классы относительных ошибок строятся (с MS Visual Studio) в отдельную библиотеку, но не в DLL.И все классы, связанные с этой ошибкой, находятся в одной и той же библиотеке.
4. Я проверил код, и кажется, что это не проблема

Было бы замечательно, если кто-нибудь сможет определитьошибка в приведенном ниже коде, и я ценю все подсказки, указывающие на решение проблемы.

РЕДАКТИРОВАТЬ:
Я забыл упомянуть ту же проблему удаления в sendThreadMain MessageSystem (см. код ниже),Если я удаляю Сообщение там, это вызывает непредвиденные ошибки где-то еще в коде.Может быть, неправильная передача данных ... но я не совсем знаю.
Этот код запускается в Windows и Linux!

Вот части кода, связанные с ошибками:

Message

class Message 
{
public:
    Message (char type, unsigned char id, unsigned short size) 
    {
        mType = type;
        mId = id;
        mSize= size;
    }

    Message(const Message &o)
    {
        mType = o.mType;
        mId = o.mId;
        mSize = o.mSize;
    }

    char getType() const {return mType;};
    unsigned char getId() const {return mId;};
    unsigned short getSize() const {return mSize;};

protected:
    char mType;
    unsigned char mId;
    unsigned short mSize;
};


class JoinMessage : public Message
{
public:
    JoinMessage () : Message ('j', 0, sizeof (JoinMessage))
    {
        team = TEAM_SPECTATOR;
    }
    JoinMessage (unsigned char id) : Message ('j', id, sizeof (JoinMessage)){}
    JoinMessage (const JoinMessage &o) : Message (o)
    {
        team = o.team;
        setName(o.getName());
    }


    void setName(std::string newName)
    {
        if (newName.length() > MAX_PLAYER_NAME_LENGHT)
            newName = newName.substr(0, MAX_PLAYER_NAME_LENGHT);

        memset(name, 0, MAX_PLAYER_NAME_LENGHT);
        for(unsigned int i = 0; i < newName.length(); i++)
            name[i] = newName[i];
    }

    std::string getName() const
    {
        std::string stringToReturn;

        for(unsigned int i = 0; i < MAX_PLAYER_NAME_LENGHT; i++)
        {
            if (name[i])
                stringToReturn.push_back(name[i]);
            else
                break;
        }

        return stringToReturn;
    }

    TeamIdentifier team;

private:
    unsigned char name[MAX_PLAYER_NAME_LENGHT];
};

// there are a lot other messages

MessageQueue

MessageQueue::~MessageQueue()
{
    boost::mutex::scoped_lock lock (queueMutex);

    while(messageQueue.size() > 0)
    {
        // the crash is non-reproducible
        // works 90% of the time
        delete messageQueue.front (); // <- Debug Assertion Failed … _BLOCK_TYPE_IS_VALID
        messageQueue.pop_front();
    }

}

void MessageQueue::enqueMessage (Message* message)
{
    {
        boost::mutex::scoped_lock lock (queueMutex);
        messageQueue.push_back(message);
    }
}

Message* MessageQueue::dequeMessage ()
{
    boost::mutex::scoped_lock lock (queueMutex);
    if (messageQueue.size() == 0) 
        return nullptr;

    Message* message = messageQueue.front ();
    messageQueue.pop_front();

    return message;
}

MessageSystem

template <class MessageType>
void broadcast (MessageType &message)
{
    MessageType *internMessage = new MessageType(message);

    boost::mutex::scoped_lock lock (mRecipientMapMutex);
    std::map <boost::asio::ip::udp::endpoint, MessageQueue *>::iterator it;

    for (it = mRecipientMap.begin ();
        it != mRecipientMap.end ();
        it++)
    {
        it->second->enqueMessage(internMessage);

    }
}


template <class MessageType>
void post (MessageType &message, boost::asio::ip::udp::endpoint &recipient)
{
    MessageType *internMessage = new MessageType(message);

    std::map <boost::asio::ip::udp::endpoint, MessageQueue* >::iterator it;
    MessageQueue *messageQueue = NULL;
    {
        boost::mutex::scoped_lock lock (mRecipientMapMutex);
        it = mRecipientMap.find (recipient);
        if (it != mRecipientMap.end())
            messageQueue = it->second;

        if(messageQueue)
            messageQueue->enqueMessage (internMessage);
    }

}


void MessageSystem::sendThreadMain ()
{
    // copy endpoints to vecotr so it can be
    // deleted from map while iterating
    std::vector<udp::endpoint> endpoints;
    {
        boost::mutex::scoped_lock lock (mRecipientMapMutex);
        std::map <udp::endpoint, MessageQueue *>::iterator mapIt = mRecipientMap.begin ();
        while (mapIt != mRecipientMap.end())
        {
            endpoints.push_back(mapIt->first);
            mapIt++;
        }
    }

    std::vector<udp::endpoint>::iterator endpointIt = endpoints.begin();
        while (endpointIt != endpoints.end())
        {
            char sendBuffer[PACKET_SIZE];
            int sendBufferPosition = 0;
            {
                boost::mutex::scoped_lock lock (mRecipientMapMutex);

                MessageQueue *messageQueue = mRecipientMap[*endpointIt];
                if (messageQueue == nullptr)
                {
                    mRecipientMap.erase(*endpointIt);
                    endpointIt++;
                    continue;
                }

                while (Message *message = messageQueue->dequeMessage ())
                {
                    if (sendBufferPosition + message->getSize() > PACKET_SIZE) 
                    {
                        // put message back and send it later
                        messageQueue->enqueMessage (message);
                        break;
                    }

                    // copy message into buffer
                    std::memcpy (
                        &sendBuffer [sendBufferPosition], message, message->getSize());

                    sendBufferPosition += message->getSize();
                    // deleting this message causes a crash if 2 or more
                    // recipients are registered within MessageSystem
                    //delete message; <- RANDOM CRASH elsewhere in the program
                }
            }
    .... // more code down here that seems not related to the error

Ответы [ 3 ]

3 голосов
/ 04 декабря 2011

Сегодня я понял это самостоятельно.Это был # 1 из 4 вариантов, упомянутых в Вопросе.

  1. удаление объектов более одного раза (путем сохранения нескольких указателей на один и тот же объект)

Вот мойРешение в MessageQueue:

template <class MessageType>
void broadcast (MessageType &message)
{
    // I was creating 1 new Message right here but I need 1 new Message
    // in EVERY MessageQueue so i moved the next line ...
    // MessageType *internMessage = new MessageType(message);

    boost::mutex::scoped_lock lock (mRecipientMapMutex);
    std::map <boost::asio::ip::udp::endpoint, MessageQueue *>::iterator it;

    for (it = mRecipientMap.begin ();
        it != mRecipientMap.end ();
        it++)
    {
        // ... down here. Now every queue contains its own copy of the Message
        MessageType *internMessage = new MessageType(message);
        it->second->enqueMessage(internMessage);
    }
}
1 голос
/ 31 августа 2013

Ну, я столкнулся с подобной проблемой, следующий код

Message* message = messageQueue.front ();
messageQueue.pop_front();

return message;

Код, который выдал ошибку со мной, был:

Point *p = q.LookFor(&q, &pts[5], &Dist);
cout ...
delete p;

Кажется, что функция удаляет созданный указательво время выполнения, так что вы не можете удалить его "снова"

, поэтому я заменил его на

Point p = *(q.LookFor(&q, &pts[5], &Dist));

, и он исчез.

1 голос
/ 02 декабря 2011

Это может быть простая проблема неправильного порядка. Вы делаете:

while(messageQueue.size() > 0)
{
    delete messageQueue.front();
    messageQueue.pop_front();
}

Может быть, удаление сообщения после того, как оно появилось, вместо того, чтобы делать это раньше, сработает:

while(messageQueue.size() > 0)
{
    Message* pFront = messageQueue.front();
    messageQueue.pop_front();
    delete pFront;
}

В любом случае, я совсем не уверен в этом решении, поскольку удаление объекта, на который указывает pFront, не должно влиять на саму очередь, которая просто хранит указатели. Но вы можете попробовать.

...