На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! Правила раздела FAQ в группе разделов С++.
1. Раздел FAQ предназначен для публикации готовых статей.
2. Здесь нельзя задавать вопросы, для этого существуют соответствующие разделы:
Чистый С++
Visual C++ / MFC / WTL / WinApi
Borland C++ Builder
COM / DCOM / ActiveX / ATL
Сопутствующие вопросы
3. Внимание, все темы и сообщения в разделе премодерируются. Любое сообщение или тема будут видны остальным участникам только после одобрения модератора.
Модераторы: B.V., Qraizer
  
> Утечка памяти в программах на языке Си , Способ нахождения
    Язык Си славится своей сложностью, и "неприкрытостью" указателей. Поэтому нет ничего странного в том, что утечка памяти так и наровит случиться, и программист часто сталкивается с необходимостью обнаружить и устранить её. Утечка памяти происходит когда программа выделяет динамическую память, и забывает её освободить. Таким образом, чем дольше программа работает, тем больше памяти использует. Рано или поздно память закончится, что приведёт к замедлению системы (и, как показывает опыт, к непредсказуемым глюкам в Windows NT). Почему-то считается, что обнаружить утечку очень сложно (ведь на первый взгляд программа работает правильно) а обнаружить в каком месте программы она происходит - ещё сложнее.

    Чтобы сэкономить человеку время и силы (пессимисты утверждают, что для того чтобы отнять у ЭВМ процессорное время и память) были разработаны специальные средства, помогающие найти ошибку: линты, профилеровщики, библиотеки. Линтами (Lint) называют программы, анализирующие исходный код, и находящие в нём места потенциальных ошибок. Не стоит ждать от линтов эффективности. Профилеровщики запускают вашу программу в виртуальной среде, и по окончании смотрят вся ли память освободилась. Библиотеки - подменяют функции менеджера памяти (malloc, calloc, realloc и free) на свои, ведущие подсчет выделяемой памяти.

    Я смотрел одну такую библиотеку под названием dmalloc. Она состоит из сотен (если не тысяч) строчек кода, снабжена файлом документации (HTML) размером более 150 kB, а на сайте (dmalloc.com) приведён длинный перечень операционных систем, в которых эта библиотека работает (Windows среди них нет, зато есть Cygwin).

    Неужели всё так сложно? Я ничего не придумывал, но естественный ход мысли (он был на 100% естественный, потому что тогда я ещё не знал про вышеописанные средства, и принцип их действия) привел меня к следующему решению. Подменить функции менеджера памяти при помощи препроцессора, примерно так:

    ExpandedWrap disabled
      static int memallocated=0;
      #ifndef NDEBUG
      #   define malloc(size) malloc((memallocated+=size, size))
      #endif


    Теперь ниже по коду выделение памяти функцией malloc будет увеличивать значение переменной memallocated (её легко отслеживать в отладчике). А функция free значит должна уменьшать memallocated. Но насколько? Ведь free не передаётся параметр, содержащий количество байт для освобождения. Я решил эту задачу при помощи хранения размера выделенной области памяти в самой области. То есть выделяется не size байт, а size+sizeof(int), в начало записывается размер, и возвращается указатель не на начало области, а на позицию после записанного нами размера, т.е. не p, а p+sizeof(int).

    Таким образом, если в конце программы переменная memallocated содержит не ноль, то мы можем заключить, что в нашей программе утечка памяти. Но где эту утечку искать? Чтобы найти её было легче, я пошёл ещё дальше, и добавил алгоритм, запоминающий на какой строчке кода и в каком файле выделялся каждый блок памяти. Вот что получилось.

    ExpandedWrap disabled
      /*  memtraces.h - replaces functions malloc, calloc, realloc and free with another
              ones that count memory being allocated. Also defines macro that allows to
              get the size of a memory block (memsize).
          Date: 2 August 2006
          Author: Jeremiah Shaulov
          Lisence: GPL
      */
      #ifndef MEMTRACES_INCLUDED
      #define MEMTRACES_INCLUDED
      #include <stdio.h>
      #include <stdlib.h>
      #include <string.h>
       
      static int memallocated=0, mempeak=0, memtraces_cnt=0, pmemtemp;
      static struct {void *p; int size; int line; char file[20];} *memtraces_var=NULL;
      static FILE *memtraces_log=NULL;
       
      #define memsize(p) ((p)==NULL ? 0 : ((int*)(p))[-1])
       
      void *realloc2(void *p, int size)
      {   int *p2;
          if (p == NULL) p2 = (int*)malloc((unsigned)(size)+sizeof(int));
          else p2 = (int*)realloc((char*)(p)-sizeof(int), (unsigned)(size)+sizeof(int));
          if (p2 == NULL)
          {   fprintf(stderr, "\nFailed to allocate %u bytes", (unsigned)(size)+sizeof(int));
              exit(1);
          }
          *p2 = size;
          return p2+1;
      }
       
      void free2(void *p)
      {   if (p != NULL) free(((int*)p) - 1);
      }
       
      void *memtraces_add(void *p, int size, int line, const char *file)
      {   memallocated += size;
          if (memallocated > mempeak) mempeak = memallocated;
          if (p == NULL) return p;
          memtraces_cnt++;
          memtraces_var = realloc(memtraces_var, memtraces_cnt*sizeof(*memtraces_var));
          memtraces_var[memtraces_cnt-1].p = p;
          memtraces_var[memtraces_cnt-1].size = size;
          memtraces_var[memtraces_cnt-1].line = line;
          if (strlen(file) <= sizeof(memtraces_var->file)-1)
              strcpy(memtraces_var[memtraces_cnt-1].file, file);
          else
              strcpy(memtraces_var[memtraces_cnt-1].file, file+strlen(file)+1-sizeof(memtraces_var->file));
          if (memtraces_log != NULL)
              fprintf(memtraces_log, "add %p of size %d; %d allocated (line %d, source %s)\n",
                  p, size, memallocated, line, file);
          return p;
      }
       
      void *memtraces_del(void *p, int line, const char *file)
      {   int i;
          if (p == NULL) return p;
          memallocated -= memsize(p);
          for (i=0; i<memtraces_cnt; i++) if (memtraces_var[i].p == p)
          {   memmove(memtraces_var+i, memtraces_var+i+1, (memtraces_cnt-i-1)*sizeof(*memtraces_var));
              memtraces_cnt--;
              memtraces_var = realloc(memtraces_var, memtraces_cnt*sizeof(*memtraces_var));
              if (memtraces_log != NULL)
                  fprintf(memtraces_log, "del %p of size %d; %d allocated (line %d, source %s)\n",
                      p, memsize(p), memallocated, line, file);
              return p;
          }
          fprintf(stderr, "free(%p) - wrong pointer (line %d, source %s)", p, line, file);
          exit(1);
          return p;
      }
       
      void memtraces(FILE *fh)
      {   int i;
          fprintf(fh, "\n\nMEMORY STATUS:\n");
          for (i=0; i<memtraces_cnt; i++)
          {   fprintf(fh, "%p of size %d (line %d, source %s)\n", memtraces_var[i].p,
                  memsize(memtraces_var[i].p), memtraces_var[i].line, memtraces_var[i].file);
          }
          fprintf(fh, "Allocated: %d; Peak: %d", memallocated, mempeak);
      }
       
      #ifdef NDEBUG
      #   define realloc(p, size) realloc2(p, size)
      #   define malloc(size) realloc2(NULL, size)
      #   define calloc(size) ( pmemtemp=(size), memset(realloc2(NULL, pmemtemp), 0, pmemtemp) )
      #   define free(p) free2(p)
      #else
      #   define realloc(p, size) ( pmemtemp=(size), memtraces_add(realloc2( \
              memtraces_del(p, __LINE__, __FILE__), pmemtemp), pmemtemp, __LINE__, __FILE__) )
      #   define malloc(size) ( pmemtemp=(size), memtraces_add(realloc2( \
              NULL, pmemtemp), pmemtemp, __LINE__, __FILE__) )
      #   define calloc(size) ( pmemtemp=(size), memset(memtraces_add(realloc2( \
              NULL, pmemtemp), pmemtemp, __LINE__, __FILE__), 0, pmemtemp) )
      #   define free(p) free2(memtraces_del(p, __LINE__, __FILE__))
      #endif
       
      #endif


    Чтобы получить подробный отчёт о состоянии памяти достаточно в начале программы написать #include "memtraces.h", и в конце вызвать memtraces(stderr).

    Как видите модуль состоит из 99 строчек кода, и основан на чистом ANSI C, поэтому будет работать на любой платформе. Недостаток - отсутствие поддержки многопоточных программ (её вы можете ввести самостоятельно путем добавления критических секций, но получится ОС-зависимо). Я не пробовал, но думаю что в C++ можно поступить аналогичным способом (там можно подменить new и delete даже не прибегая к помощи препроцессора).

    Вот несколько других решений утечки памяти: valgrind (все хвалят; только Линукс), dmalloc, ccmalloc, LeakTracer, YAMD.

    P.S. Отредактировал 2 August 2006. Исправил ошибку.
    Сообщение отредактировано: polyglott -
      Такой же способ для С++.
      Он не претендует на всецелосность (ибо в программе на С++ можно выделять память при помощью malloc/calloc ), а так же он, конечно, не отловит объекты, которые создавались в других библиотеках (CreateObject и т.п.).

      Основные идеи:
      Нельзя использовать стандартный коллектор (map,list и пр) так как в них самих используются new/delete. Написание своего аллокатора не помогает. (Во всяком случае, у меня не получилось =) )
      Поэтому я написал небольшой класс, который добавляет/удаляет структуры с описанием выделенной памяти.

      У меня вся информация показывается, когда срабатывает конструктор этого класса. Так как объект класса - глобальный, он уничтожится автоматически (естественно, при корректном выходе из программы) после выполнения главной функции. А так как он, по идее, должен создаваться первым, то и уничтожаться последним.
      Но никто не запрещает самому вызвать mem.PrintLeaks();

      Вывод осуществляется в окно output (в студии >= 6.0.) В остальных компиляторах не тестировал, не знаю, есть ли такая функция и такая возможность. Строка вывода составлена таким образом, чтобы при двойном клике на этой строка компилятор кидал вас в то место, где была выделена память.

      В целях оптимизации, пихаю структуры в список в начало ( ~push_front ). Идея в том, что при удалении должны, по идее, удаляться указатели по принципу FIFO.

      Для использования достаточно включить этот файл где-нибудь в первом файле и написать:
      ExpandedWrap disabled
        #ifdef _DEBUG
        #include "ваш_файл.h"
        #define new DEBUG_NEW
        #endif


      ExpandedWrap disabled
        #include <stdio.h>
        struct MemLeak
        {
            void        *ptr;
            size_t      size;
            const char  *file;
            int         line;
        };
         
        #define INFO_LEN 300
         
        class CMemCollect
        {
            struct Collector
            {
                MemLeak leak;
                Collector * next;
                Collector * prev;
            };
         
            Collector *m_Start;
         
            void PrintStr(char * a_Str)
            {
                OutputDebugStringA( a_Str );
            }
         
            void PrintInfo(MemLeak * a_pLeak)
            {
                char strInfo[INFO_LEN];
                if( a_pLeak->file )
                    sprintf(strInfo,"%s(%d) : size = %d\n",a_pLeak->file,a_pLeak->line,a_pLeak->size);
                else
                    sprintf(strInfo,"size = %d\n",a_pLeak->size);
         
                PrintStr(strInfo);
            }
         
            Collector * GetLast()
            {
                Collector *iter = m_Start;
                if( !iter )
                    return NULL;
         
                while ( iter->next )
                {
                    iter = iter->next;
                }
                return iter;
            }
        public:
            CMemCollect()
            {
                m_Start = NULL;
            }
         
            ~CMemCollect()
            {
                PrintLeaks();
            }
         
            void PrintLeaks()
            {
                Collector *iter = GetLast();
                if( iter )
                    PrintStr("-=MEMORY LEAK DETECTED!=-\n");
         
                while( iter != NULL )
                {
                    MemLeak *str = &iter->leak;
         
                    PrintInfo(str);
         
                    Collector * prevIter = iter->prev;
                    Remove( iter );
                    iter = prevIter;
                }
            }
         
            void Add(MemLeak & a_pLeak)
            {
                Collector *newStr = (Collector*)malloc(sizeof(Collector));
                if( !newStr )
                    return;
         
         
                memset(newStr,0,sizeof(Collector));
                memcpy(&newStr->leak,&a_pLeak,sizeof(MemLeak));
         
                if( m_Start )
                {
                    newStr->next    = m_Start;
                    m_Start->prev   = newStr;
                }
         
                m_Start = newStr;
            }
         
            void Remove(Collector *iter)
            {
                if( iter->prev )
                    iter->prev->next = iter->next;
         
                if( iter->next )
                    iter->next->prev = iter->prev;
         
                if( iter == m_Start )
                    m_Start = iter->next;
         
                free(iter);
            }
         
            void Remove(void * ptr)
            {
                Collector *iter = m_Start;
                while( iter != NULL )
                {
                    if( iter->leak.ptr == ptr )
                    {
                        Remove(iter);
                        return;
                    }
         
                    iter = iter->next;
                }
            }
        };
         
        CMemCollect mem;
         
        void * operator new( size_t size , const char* lpszFileName, int nLine )
        {
            void * ptr = malloc( size );
            if ( !ptr )
                return NULL;
         
            MemLeak leak    = {0};
            leak.ptr        = ptr;
            leak.file       = lpszFileName;
            leak.line       = nLine;
            leak.size       = size;
         
         
            mem.Add(leak);
            
            return ptr;
        }
         
        void * operator new( size_t size )
        {
            void * ptr = malloc( size );
            if ( !ptr )
                return NULL;
         
            MemLeak leak    = {0};
            leak.size       = size;
            leak.ptr        = ptr;
         
            mem.Add(leak);
         
            return ptr;
        }
         
        void operator delete( void *  ptr , const char* lpszFileName, int nLine )
        {
            mem.Remove( ptr );
         
            free( ptr );
        }
         
        void operator delete(void *  ptr)
        {
            mem.Remove( ptr );
            free( ptr );
        }
         
        #define DEBUG_NEW new(__FILE__,__LINE__)
        Hsilgos
        malloc, насколько мне известно, непотокобезовасна в отличие от new. В многопоточной программе при активном выделении памяти куча скорей всего подпортится.
        Предлагаю добавить класс-заглушку, которых будет взависимости от ОС и наличия многопоточности выполнять синхронизацию.
        Объекты синхронизации, например, в винде критическая секция, в никсах мютекс (mutex_lock(...),mutex_unlock(...) ,если память не изменяет :unsure: ) или просто быть пустышкой для однопоточных программ.
        Сообщение отредактировано: ElcnU -
          ElcnU
          Объект, который будет безопасно выделять память? чёт не догнал немного =)
          Тогда нужно всю функцию "add" загнать в критическую секцию...
          Синхронизация - моя слабость. Я с многопоточностью хоть и работал, но редко где приходилось синхронизировать =(
            Цитата Hsilgos @
            Объект, который будет безопасно выделять память? чёт не догнал немного =)
            Тогда нужно всю функцию "add" загнать в критическую секцию...
            Синхронизация - моя слабость. Я с многопоточностью хоть и работал, но редко где приходилось синхронизировать =(

            я имел в виду написать класс обёртку для объектов синхронизации
            и выглядеть в конечном счёте должно примерно так
            ExpandedWrap disabled
              static CMemCollect mem;//статик чтоб один хедер могли подключать несколько сишников
              static CSync MemLeakSync;
              void * operator new( size_t size , const char* lpszFileName, int nLine )
              {
                  MemLeakSync.Lock();
                  void * ptr = malloc( size );
                  MemLeakSync.Unlock();
                  if ( !ptr )
                      return NULL;
               
              ...
                  MemLeakSync.Lock();
                    free( ptr );
                  MemLeakSync.Unlock();
              ...

            что нить типа того
            ExpandedWrap disabled
              #ifdef MEMLEAK_WIN32
                #include <windows.h>
              #endif
              #ifdef MEMLEAK_NIX
                #include <pthread.h>
              #endif
               
              class CSync
              {
              private:
              #ifdef MEMLEAK_WIN32
                CRITICAL_SECTION m_CS;
              #endif
              #ifdef MEMLEAK_NIX
                pthread_mutex_t m_Mutex;
              #endif
              public:
                CSync()
                {
                  //в зависимости от продефайненых параметров производится инициализация объекта синхронизации под нужную платформу типа
                  #ifdef MEMLEAK_WIN32
                    InitializeCriticalSection(&m_CS);
                  #endif
                  #ifdef MEMLEAK_NIX
                    pthread_mutex_init(&m_Mutex, NULL);
                  #endif
              ...  
                }
                ~CSync()
                {
                  #ifdef MEMLEAK_WIN32
                    DeleteCriticalSection(&m_CS);
                  #endif
                  #ifdef MEMLEAK_NIX
                    pthread_mutex_destroy(&m_Mutex, NULL);
                  #endif
              ...  
                }
                void Lock()
                {
                  #ifdef MEMLEAK_WIN32
                    EnterCriticalSection(&m_CS);
                  #endif
                  #ifdef MEMLEAK_NIX
                    pthread_mutex_lock(&m_Mutex);
                  #endif    
              ...
                }
                void Unlock()
                {
                  #ifdef MEMLEAK_WIN32
                    LeaveCriticalSection(&m_CS);
                  #endif
                  #ifdef MEMLEAK_NIX
                    pthread_mutex_unlock(&m_Mutex);
                  #endif    
              ...
                }
              ...
              }

            соответственно если MEMLEAK_ХХХ не был продефайнен, то класс получиться пустой, для экономии ресурсов в однопоточный приложениях
            Сообщение отредактировано: ElcnU -
              Значит добавляем 2 класса =)
              Небольшой шаблон для автоматического "переключения". В конструкторе вызывает первую функцию, в деструторе - вторую.
              Я успешно использовал его для залочивания перерисовки, пока отрабатывает метод.
              ExpandedWrap disabled
                template <class T>
                class CAutoSwitcher
                {
                protected:
                    typedef void(T::*ClassMember)(void) ;
                 
                    ClassMember m_MemStart;
                    ClassMember m_MemFinish;
                 
                    T* m_ptClass;
                    CAutoSwitcher(){};// no create with default construtor
                public:
                    CAutoSwitcher(T* ptClass,void(T::*mem_on)(void),void(T::*mem_off)(void))
                    {
                        m_MemStart  = mem_on;
                        m_MemFinish = mem_off;
                        m_ptClass   = ptClass;
                 
                        if(m_ptClass && m_MemStart )
                            ( m_ptClass->*m_MemStart )();
                    }
                    virtual ~CAutoSwitcher()
                    {
                        if(m_ptClass && m_MemFinish )
                            ( m_ptClass->*m_MemFinish )();
                    }
                };


              Ну и, собственно, сам класс для синхронизации (только Вынь32):
              ExpandedWrap disabled
                class CSync
                {
                    CRITICAL_SECTION m_crSect;
                public:
                    CSync()
                    {
                        Init();
                    }
                    ~CSync()
                    {
                        Destroy();
                    }
                 
                 
                    void Init();
                    void Destroy();
                    void Lock();
                    void UnLock();
                };
                 
                void CSync::Init()
                {
                    InitializeCriticalSection(&m_crSect);
                }
                 
                void CSync::Destroy()
                {
                    DeleteCriticalSection(&m_crSect);
                }
                 
                void CSync::Lock()
                {
                    EnterCriticalSection(&m_crSect);
                }
                 
                void CSync::UnLock()
                {
                    LeaveCriticalSection(&m_crSect);
                }
                 
                CSync g_Sync;
                 
                #define LOCK_METHOD() CAutoSwitcher<CSync> lck(&g_Sync,&CSync::Lock,CSync::UnLock);


              В new/delete в самом начале пишем LOCK_METHOD()
                > malloc, насколько мне известно, непотокобезовасна в отличие от new.

                ээ, что за глупость? во всяком случае в винде нт это сводится к HeapAlloc(), т.е. RtlAllocateHeap, которая активно юзает EnterCriticalSection и LeaveCriticalSection.
                А new - сводится к malloc и по сути является тем же самым - только ещё конструкторы всякие вызываются, экземплеры классов инициализируются и т.п., но память через malloc выделяется...
                  Цитата Throne @
                  > malloc, насколько мне известно, непотокобезовасна в отличие от new.

                  ээ, что за глупость? во всяком случае в винде нт это сводится к HeapAlloc(), т.е. RtlAllocateHeap, которая активно юзает EnterCriticalSection и LeaveCriticalSection.
                  А new - сводится к malloc и по сути является тем же самым - только ещё конструкторы всякие вызываются, экземплеры классов инициализируются и т.п., но память через malloc выделяется...

                  верное замечание :yes: . вчера сам копался в crt исходниках, и, по крайней мере, в студийных(vc2005) исходниках так и сделано.
                  а вот как дела обстоят на других платформах для меня это еще под большим вопросом :unsure: ? да и вообще в стандарте навряд ли сказано чтото о многопоточности...
                  про new согласен, просто было малость другое убеждение:(
                  ну по крайней мере не будет лишним синхронизовать такие вещи
                  Цитата Hsilgos @
                  ExpandedWrap disabled
                            if( m_Start )
                            {
                                newStr->next    = m_Start;
                                m_Start->prev   = newStr;
                            }
                  Сообщение отредактировано: ElcnU -
                    Цитата
                    но память через malloc выделяется...
                    Это не обязательно. Стандарт разрешает даже иметь отдельные "свободные памяти" для C-функций и C++-операторов.
                      Throne,
                      А что вы имеете в виду под непотокобезовасными функциями?
                        Цитата ElcnU @
                        malloc, насколько мне известно, непотокобезовасна в отличие от new.

                        откуда инфа ? :huh:
                        какая может быть потокобезопасность, если в стандарте понятия многопоточности просто нет ?
                          Цитата gena_dj @
                          Throne,
                          А что вы имеете в виду под непотокобезовасными функциями?

                          это он меня цитировал.
                          в общих чертах отсутствие синхронизации доступа к общим участкам памяти из различных потоков

                          Цитата C06akaDuka @
                          откуда инфа ?

                          про new была статья, точно не помню откуда, вот оттуда, но насчет этого я уже отписался в 8м посту :yes-sad:

                          Цитата Throne @
                          ээ, что за глупость? во всяком случае в винде нт это сводится к HeapAlloc(), т.е. RtlAllocateHeap, которая активно юзает EnterCriticalSection и LeaveCriticalSection.
                          А new - сводится к malloc и по сути является тем же самым - только ещё конструкторы всякие вызываются, экземплеры классов инициализируются и т.п., но память через malloc выделяется...

                          это точно в crt исходниках от msvc.
                          а, например, в ucLinux сборке под ADSP-BF537, нет никакой синхронизации, то есть в таких системах необходимо выполнять синхронизацию при выделении памяти, если работают несколько потоков...
                          ЗЫ: через телнет проблематично отлавливать косяки, особенно если это проблемы с кучей(у ucLinux просто неадекватная реакция на этот счет бывает) :yes: .
                          Сообщение отредактировано: ElcnU -
                            Цитата ElcnU @
                            отсутствие синхронизации доступа к общим участкам памяти из различных потоков

                            Зачем нужна синхронизация? Как она влияет на выделение памяти? Выделенная память всегда привязана к процессу, а не к потокам.

                            Скорее всего в статье имеется в виду следующее. При использовании new после вызова _endthread память, выделенная в потоке, будет освобождена.
                              Цитата gena_dj @
                              Зачем нужна синхронизация? Как она влияет на выделение памяти?
                              Возможна ситуация, когда один поток запросил блок памяти в процессе обработки запроса от другого потока. Это не говоря про многоядерные/многопроцессорные системы.
                                Цитата trainer @
                                один поток запросил блок памяти в процессе обработки запроса от другого потока.

                                Пямять запрашивается из кучи процесса.
                                Каждый поток имеет только свой персональный стек.
                                Поэтому такие запросы обработаются корректно.
                                Цитата trainer @

                                Это не говоря про многоядерные/многопроцессорные системы.

                                Это ничего не изменит.
                                  Цитата gena_dj @
                                  Пямять запрашивается из кучи процесса.
                                  Во-первых, иногда между кучей процесса и функциями вроде malloc стоит посредник. Во-вторых, выделение памяти - не атомарная операция. Если уж непотокобезопасна операция простого увеличения переменной вроде:
                                  ExpandedWrap disabled
                                    a += 2;
                                  , то гораздо более сложная процедура выделения памяти - тем более. Поэтому если в менеджере памяти не озадачились синхронизацией - придется делать ее ручками.
                                  Цитата gena_dj @
                                  Это ничего не изменит.
                                  Это изменит многое. см. выше.
                                    trainer,
                                    это Вы зря.
                                    Все виндовые xAlloc() тщательно тестируются и полностью потокобезопасны. Не будет такого, чтобы двум одновременным потокам, вызывающим xAlloc() вернулся один и тот же указатель. Даже в случае многопроцессорности.
                                      Цитата gena_dj @
                                      Все виндовые xAlloc()
                                      За пределами Microsoft жизни не существует?
                                        Сущствует конечно,
                                        но на предыдущей странице почему-то фигурирует EnterCriticalSection() и LeaveCriticalSection()
                                        Про выделение памяти за пределами Microsoft не могу ничего сказать.
                                            Цитата gena_dj @
                                            Не будет такого, чтобы двум одновременным потокам, вызывающим xAlloc() вернулся один и тот же указатель. Даже в случае многопроцессорности.


                                            В случае, если линкуемся с многопоточным рантаймом. Если же слинкуемся с обычным - здравствуй, лотерея.

                                            Сообщения были разделены в тему "Spam"
                                              Как раз про утечку памяти рассказывают почти исключительно адепты решётки и ей подобных. Наталкивает на мысль, что именно решётка и необходима, чтоб утечку организовать. Выделение и парное к нему освобождение памяти всегда делается в связке: написал закорючку для выделения, сразу учитываешь в освобождении. Как можно умудриться напороться на утечку? Хотя, я разок справился. Но на указателях, инкапуслированных в самую глубину. На плюсах. Странно было, что я в тот раз клаву с мышью не перепутал. Исправил после первого же теста. Без логов, профайлеров, с наглухо отвалившимся дебагером.
                                              Сообщение отредактировано: Ирокез -
                                              0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                              0 пользователей:


                                              Рейтинг@Mail.ru
                                              [ Script execution time: 0,0654 ]   [ 16 queries used ]   [ Generated: 28.03.24, 18:25 GMT ]