Вопрос

Я работаю над процессором запроса, который читает в длинных списках идентификатора документа из памяти и ищет соответствующий идентификатор. Когда он находит одно, он создает структуру DOC, содержащую docid (int) и ранг документа (двойной) и подталкивает его к очереди приоритета. Моя проблема заключается в том, что когда Word (ы) искали, имеет длинный список, когда я пытаюсь протолкнуть документ на очередь, я получаю следующее исключение: необработанное исключение в 0x7C812AFB в QueryProcessor.exe: исключение Microsoft C ++: STD: : bad_alloc в памяти Местоположение 0x0012ee88 ..

Когда слово имеет короткий список, он работает нормально. Я пытался толкать док на очередь в нескольких местах в моем коде, и все они работают до определенной линии; После этого я получаю вышеуказанную ошибку. Я полностью в потере от того, что не так, потому что самый длинный список прочитал менее 1 МБ, и я освобождаю всю память, которую я выделяю. Почему вдруг не может быть исключением Bad_alloc, когда я пытаюсь протолкнуть документ на очередь, которая имеет емкость для его удержания (я использовал вектор с достаточным количеством пространства, зарезервированной в качестве основной структуры данных для очереди приоритета)?

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

Функция NEXTGEQ считывает список сжатых блоков блока DOCIDS по блоку. То есть, если он видит, что LastDocid в блоке (в отдельном списке) больше, чем DOCID, прошедший, он раздает блок и поиск, пока не найдет правильный. Каждый список начинается с метаданных о списке с длиной каждого сжатого куска и последнего DOCID в кусочке. Data.iquery указывает на начало метаданных; data.metapointer указывает на то, где бы в метаданных работает функция в настоящее время; и data.blockpointer указывает на начало блока несжатых документов, если есть один. Если он видит, что это уже было распаковано, это просто ищет. Ниже, когда я вызываю функцию в первый раз, он распадает блок и находит dociD; Толкание на очередь после этого работает. Во второй раз ему даже не нужно распаковать; То есть новая память не выделяется, но после этого времени нажав в очередь, дает ошибку Bad_alloc.

Редактировать: Я более убрал свой код, чтобы он мог составить. Я также добавил в функции OpenList () и функциями Nextgeq, хотя последняя длинная, потому что я думаю, что проблема вызвана повреждением кучи где-то в ней. Большое спасибо!

struct DOC{

    long int docid;
    long double rank;

public:
    DOC()
    {
        docid = 0;
        rank = 0.0;
    }

    DOC(int num, double ranking)
    {
        docid = num;
        rank = ranking;

    }

     bool operator>( const DOC & d ) const {
       return rank > d.rank;
    }

      bool operator<( const DOC & d ) const {
       return rank < d.rank;
    }
    };

struct listnode{

int* metapointer;
int* blockpointer;
int docposition;
int frequency;
int numberdocs;
int* iquery;
listnode* nextnode;

};

void QUERYMANAGER::SubmitQuery(char *query){

    listnode* startlist;

        vector<DOC> docvec;
        docvec.reserve(20);
        DOC doct;


    //create a priority queue to use as a min-heap to store the documents and rankings;


        priority_queue<DOC, vector<DOC>,std::greater<DOC>> q(docvec.begin(), docvec.end());

        q.push(doct);

    //do some processing here; startlist is a pointer to a listnode struct that starts the   //linked list

        //point the linked list start pointer to the node returned by the OpenList method

        startlist = &OpenList(value);
        listnode* minpointer;
        q.push(doct);


        //start by finding the first docid in the shortest list
            int i = 0;
            q.push(doct);
            num = NextGEQ(0, *startlist);
            q.push(doct);
            while(num != -1)
               {

            q.push(doct);

    //the is where the problem starts - every previous q.push(doct) works; the one after
    //NextGEQ(num +1, *startlist) gives the bad_alloc error

            num = NextGEQ(num + 1, *startlist);

         //this is where the exception is thrown
            q.push(doct);               
        }

    }



//takes a word and returns a listnode struct with a pointer to the beginning of the list
//and metadata about the list 
listnode QUERYMANAGER::OpenList(char* word)
{
    long int numdocs;

    //create a new node in the linked list and initialize its variables


    listnode n;
    n.iquery = cache -> GetiList(word, &numdocs);
    n.docposition = 0;
    n.frequency = 0;
    n.numberdocs = numdocs;

   //an int pointer to point to where in the metadata you are
    n.metapointer = n.iquery;
    n.nextnode = NULL;
  //an int pointer to point to the uncompressed block of data, if there is one
    n.blockpointer = NULL;



    return n;


}


int QUERYMANAGER::NextGEQ(int value, listnode& data)
{
     int lengthdocids;
     int lengthfreqs; 
     int lengthpos;
     int* temp;
     int lastdocid;


     lastdocid = *(data.metapointer + 2);

while(true)
{

         //if it's not the first chunk in the list, the blockpointer will be pointing to the 
        //most recently opened block and docpos to the current position in the block
    if( data.blockpointer && lastdocid >= value)
    {

            //if the last docid in the chunk is >= the docid we're looking for,
            //go through the chunk to look for a match


        //the last docid in the block is in lastdocid; keep going until you hit it
        while(*(data.blockpointer + data.docposition) <= lastdocid)
        {
            //compare each docid with the docid passed in; if it's greater than or equal to it, return a pointer to the docid
             if(*(data.blockpointer + data.docposition ) >= value)
             {

                 //return the next greater than or equal docid
                 return *(data.blockpointer + data.docposition);
             }
             else
             {
                 ++data.docposition;
             }
        }

        //read through the whole block; couldn't find matching docid; increment metapointer to the next block;
        //free the block's memory

        data.metapointer += 3;
        lastdocid = *(data.metapointer + 3);
        free(data.blockpointer);
        data.blockpointer = NULL;
    }


        //reached the end of a block; check the metadata to find where the next block begins and ends and whether 
        //the last docid in the block is smaller or larger than the value being searched for


        //first make sure that you haven't reached the end of the list
            //if the last docid in the chunk is still smaller than the value passed in, move the metadata pointer
           //to the beginning of the next chunk's metadata; read in the new metadata


            while(true)
         //  while(*(metapointers[index]) != 0 )
           {
               if(lastdocid < value && *(data.metapointer) !=0)
               {
               data.metapointer += 3;
               lastdocid = *(data.metapointer + 2);
               }


           else if(*(data.metapointer) == 0)
           {
               return -1;
             }

           else
               //we must have hit a chunk whose lastdocid is >= value; read it in
           {
                //read in the metadata
           //the length of the chunk of docid's is cumulative, so subtract the end of the last chunk 
           //from the end of this chunk to get the length

               //find the end of the metadata


                temp = data.metapointer;

            while(*temp != 0)
            {
                temp += 3;
            }
                temp += 2;
    //temp is now pointing to the beginning of the list of compressed data; use the location of metapointer
    //to calculate where to start reading and how much to read

         //if it's the first chunk in the list,the corresponding metapointer is pointing to the beginning of the query
        //so the number of bytes of docid's is just the first integer in the metadata
                if(  data.metapointer == data.iquery)
                {
                    lengthdocids = *data.metapointer;

                }

                else
                {
                    //start reading from the offset of the end of the last chunk (saved in metapointers[index] - 3)
                    //plus 1 = the beginning of this chunk

                    lengthdocids = *(data.metapointer) - (*(data.metapointer - 3));
                    temp += (*(data.metapointer - 3)) / sizeof(int); 

                   }


           //allocate memory for an array of integers - the block of docid's uncompressed
           int* docblock = (int*)malloc(lengthdocids * 5 );

           //decompress docid's into the block of memory allocated
            s9decompress((int*)temp, lengthdocids /4, (int*) docblock, true);

            //set the blockpointer to point to the beginning of the block
            //and docpositions[index] to 0
            data.blockpointer = docblock;
            data.docposition = 0;
            break;

                }

           } 

}
}

Большое спасибо, BSG.

Это было полезно?

Решение

Предполагая, что у вас есть коррупция кучи и на самом деле не на самом деле исчерпывающая память, самый распространенный, самый распространенный. Вы вполне можете легко узнать, если это проблема, просто комментируя все ваши звонки, чтобы удалить (или бесплатно). Это приведет к тому, что ваша программа утечна как сито, но если на самом деле не сражается, вы, вероятно, определили проблему.

Другая общая причина причины коррумпированной кучи - удаление (или освобождение) указатель, который никогда не выделялся на кучу. Дифференциация между двумя причинами коррупции не всегда легко, но ваш первый приоритет должен быть выяснен, если коррупция на самом деле проблема.

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

Другие советы

QUERYMANAGER::OpenList Возвращает listnode по значению. В startlist = &OpenList(value); Затем вы приступаете, чтобы получить адрес временного объекта, который возвращается. Когда временный уходит, вы можете получить доступ к данным некоторое время, а затем он перезаписан. Не могли бы вы только объявить не указатель ListNode StartList на стеке и назначьте его возвращаемое значение напрямую? Затем удалите * перед другим использованием и посмотрите, исправляет ли это проблему.

Еще одна вещь, которую вы можете попробовать, заменяет все указатели со смарт-указателями, специально что-то вроде boost::shared_ptr<>, В зависимости от того, сколько кода это действительно и насколько вам удобно автоматизировать задачу. Умные указатели не отвечают на все, но они, по крайней мере, безопаснее, чем сырые указатели.

Спасибо за вашу помощь. Вы были правы, Нил - мне, должно быть, сумели испортить мою кучу. Я до сих пор не уверен, что это вызывает, но когда я поменял Malloc (NumdoCids * 5) в Malloc (256), оно волшебно остановился сбой. Полагаю, я должен был проверить, действительно ли мои малокс на самом деле преуспели! Спасибо еще раз! BSG.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top