2011-12-02 6 views
16

Ho una perdita di memoria veramente brutta che sto cercando di risolvere, ma in qualche modo non sono in grado di eliminare gli oggetti senza attivare questa asserzione.Assunzioni di debug non riuscite ... _BLOCK_TYPE_IS_VALID (pHead-> nBlockUse)

Ho cercato una soluzione tramite Google e ho letto le domande su StackOverflow su questo errore ma non ero ancora in grado di trovare la risposta!

possibili ragioni per ottenere questo errore secondo la mia ricerca: oggetti
1. eliminazione più di un
2. ombra copia
3. Creazione ed eliminazione di oggetti che vengono caricati da una DLL esterna
4. creazione gli oggetti senza memorizzare il puntatore

MA:
1. ho controllato il codice e non sono riuscito a trovare doppia eliminazione
2. io uso un costruttore di copia per copiare gli oggetti
3. Le classi di relatet Error sono compilate (con MS Visual Studio) in una lib separata ma non in una DLL. E tutte le classi correlate a questo errore si trovano nella stessa lib.
4. Ho controllato il codice e sembra che non è questo il problema

Sarebbe bello se qualcuno è in grado di individuare l'errore nel codice qui sotto, e mi rendo conto ogni suggerimento che mi punta alla soluzione del problema.

MODIFICA:
Ho dimenticato di menzionare lo stesso problema di eliminazione in sendThreadMain di MessageSystem (vedere il codice seguente). Se elimini il messaggio lì causa errori imprevisti da qualche altra parte nel codice. Potrebbe essere solo una trasmissione dati sbagliata ... ma non lo so davvero.
Questo codice è eseguito su Windows e Linux!

Ecco l'errore relativi parti del codice:

Messaggio

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 
+0

Non si aggiungono messaggi alla coda in nessun altro posto rispetto alla funzione 'broadcast'? –

+0

Ci sono buone notizie e cattive notizie. La buona notizia è che questo sicuramente non è causato da una perdita di memoria. –

+0

Non sono sicuro se questo è il problema ma dovresti avere un distruttore virtuale nella classe Message. –

risposta

3

Oggi ho capito da solo. Era il # 1 delle 4 possibilità menzionate nella domanda.

  1. eliminare gli oggetti più di una volta (salvando più puntatori a esattamente lo stesso oggetto)

Qui è la mia soluzione in 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

Potrebbe essere un semplice pro blem di ordine sbagliato. Si sta facendo:

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

Forse l'eliminazione del messaggio dopo popping, invece di prima, avrebbe fatto il trucco:

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

In ogni caso, io non sono sicuro affatto su questa soluzione, dal momento che l'eliminazione del l'oggetto puntato da pFront non dovrebbe avere alcun effetto sulla coda stessa, che memorizza semplicemente i puntatori. Ma puoi provare.

+1

Penso anche che non dovrebbe avere alcun effetto sulla coda, ma ci proverò comunque. Ma sembra essere un altro problema dal momento che l'eliminazione dei messaggi non funziona dopo averli rimossi dalla coda (vedere il ciclo while alla fine di MessageSystem) – cwin

1

Beh, ho dovuto affrontare problemi simili, il seguente codice

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

return message; 

Il codice che ha prodotto l'errore con me era:

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

Sembra che la funzione di eliminare il puntatore si crea nel runtime, quindi non è permesso di eliminarlo "di nuovo"

così ho sostituito con

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

ed è sparito.

Problemi correlati