2011-12-02 14 views
16

Mam bardzo zły wyciek pamięci próbuję naprawić, ale jakoś nie jestem w stanie usunąć obiektów bez wywoływania tego asercji.Asercja debugowania nie powiodła się ... _BLOCK_TYPE_IS_VALID (pHead-> nBlockUse)

Szukałem rozwiązania za pośrednictwem Google i przeczytałem pytania dotyczące stackoverflow na temat tego błędu, ale wciąż nie byłem w stanie znaleźć odpowiedzi!

Możliwe powody, aby uzyskać ten błąd według moich badań:
1. Usuwanie obiektów więcej niż jeden
2. kopiowania cień
3. Tworzenie i usuwanie obiektów, które są ładowane z zewnętrznych bibliotek DLL
4. tworzeniu obiektów bez zapisywania wskaźnik

ALE:
1. Sprawdziłem kod i nie był w stanie znaleźć podwójną delecją
2. Używam konstruktor kopiujący skopiować obiekty
3. Klasy relacji błędów są kompilowane (z MS Visual Studio) do oddzielnej biblioteki, ale nie do biblioteki dll. ORAZ wszystkie klasy powiązane z tym błędem znajdują się w tej samej bibliotece.
4. Sprawdziłem kod i wygląda na to, że to nie jest problem.

Byłoby wspaniale, gdyby ktokolwiek był w stanie dostrzec błąd w kodzie poniżej i doceniam każdą podpowiedź, która wskazuje mi na rozwiązanie problem.

EDYTOWANIE:
Zapomniałem wspomnieć o tym samym problemie z usuwaniem w sendThreadMain MessageSystem (zobacz poniższy kod). Jeśli usunę tę wiadomość, spowoduje to nieoczekiwane błędy w innym miejscu kodu. Może po prostu źle przekazać dane ... ale tak naprawdę nie wiem.
Ten kod jest uruchamiany w systemach Windows i Linux!

Oto błędzie związanym z częściami kodu:

Wiadomość

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 

kolejka komunikatów

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

Nie dodajesz wiadomości do kolejki w żadnym innym miejscu niż funkcja 'broadcast'? –

+0

Jest dobra wiadomość i złe wieści. Dobra wiadomość jest taka, że ​​to zdecydowanie nie jest spowodowane wyciekiem pamięci. –

+0

Nie jestem pewien, czy to jest problem, ale powinieneś mieć wirtualny destruktor w wiadomości klasy. –

Odpowiedz

3

Dzisiaj wymyśliłem to na własną rękę. Było to # 1 z 4 możliwości wymienionych w pytaniu.

  1. usuwanie obiektów więcej niż jeden raz (zapisując wiele wskazówek do dokładnie tego samego obiektu)

Oto moje rozwiązanie w kolejka komunikatów:

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

To może być prosty pro błąd złego porządku. Robisz:

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

Może usuwanie wiadomości po popping go, zamiast wcześniej, by rade:

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

Zresztą, nie jestem przekonany, wcale się na to rozwiązanie, ponieważ usuwając obiekt wskazany przez pFront nie powinien mieć wpływu na samą kolejkę, która po prostu przechowuje wskaźniki. Ale możesz spróbować.

+1

Uważam też, że nie powinno to mieć wpływu na kolejkę, ale i tak spróbuję. Ale wydaje się, że jest to inny problem, ponieważ usuwanie wiadomości nie działa po usunięciu ich z kolejki (patrz pętla while na końcu MessageSystem) – cwin

1

Cóż, w obliczu podobnego problemu, następujący kod:

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

return message; 

The Kod, który produkowany był błąd ze mną:

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

Wydaje się, że funkcja usuwania wskaźnik to tworzy się w czasie pracy, więc nie wolno go usuwać „ponownie”

więc zastąpił go

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

i już go nie ma.

Powiązane problemy