zlib inflateReset вызывает утечку памяти (нет)

В настоящее время я работаю над приведенным ниже требованием. Вот требование: на стороне сервера большой файл делится на 4000-байтовые блоки (кадры). Каждый блок, в свою очередь, сжимается (используя zlib) и отправляется клиентскому процессу. Например, если размер файла составляет 12000 байт, он разделяется на 3 блока.

Выше файл будет иметь 3 блока => Блок-0, Блок-1, Блок-2

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

Я написал подпрограмму inflateData, которая выполняет следующие действия на основе полученного блока:

Когда первый блок получен, - inflateInit - inflate - inflateReset Когда получены промежуточные блоки, - inflate - inflateReset Когда последний блок получен, - inflate - inflateEnd

С помощью описанной выше процедуры распаковка блоков происходит, как и ожидалось. Но проблема, с которой я сталкиваюсь, заключается в том, что она потребляет много памяти и в какой-то момент вся система замедляется. При проверке с помощью valgrind утечка памяти сообщается с помощью inflateInit2_. Это приводит к исчерпанию системных ресурсов.

== 30359 == 57,312 байт в 6 блоках, возможно, потеряны в записи потерь 64 из 67

== 30359 == в 0x4A069EE: malloc (vg_replace_malloc.c: 270)

== 30359 == по 0x3E57808F1E: inflateInit2_ (в /lib64/libz.so.1.2.3)

== 30359 == по 0x40C220: inflateData (productMaker.c:1668)

Ниже приводится процедура inflateData.

    int inflateData(
    char*    const    inBuf,                  
    unsigned long     inLen,                  
    unsigned int      isFirstBlk,
    unsigned int      isLastBlk,
    const    char*    outBuf,                 
    unsigned long*     outLen)                 
{

  int have;
  int readsz;
  int bsize;
  static z_stream zstrm;
  int zerr;
  int flush;
  char out[CHUNK_SZ];
  char in[CHUNK_SZ];
  int ret,nwrite,idx = -1;
  int savedByteCntr=0;
  unsigned char *dstBuf;
  int  firstCall = 1;
  int totalBytesIn=0;
  int inflatedBytes=0;
  int decompByteCounter = 0;
  int num=0;


  ret = Z_OK;
  readsz = 0;
  bsize = CHUNK_SZ;

  dstBuf = (unsigned char *) outBuf;

  if(isFirstBlk){
        memset(&zstrm, '\0', sizeof(z_stream));
        zstrm.zalloc = Z_NULL;
        zstrm.zfree = Z_NULL;
        zstrm.opaque = Z_NULL;

        if ((zerr = inflateInit(&zstrm)) != Z_OK) {
                uerror("ERROR %d inflateInit (%s)",
                        zerr, decode_zlib_err(zerr));
                return -1;
        }
  }

    while(totalBytesIn < inLen ) {
      int compChunkSize = ((inLen - totalBytesIn) > 5120) ? 5120 :
                                                  (inLen - totalBytesIn);
      memcpy(in, inBuf + totalBytesIn, compChunkSize);

      zstrm.avail_in = inLen - totalBytesIn;
      zstrm.next_in = in ;

      zstrm.avail_out = CHUNK_SZ;
      zstrm.next_out = out;
      inflatedBytes = 0;

      while(ret != Z_STREAM_END) {
         ret  = inflate(&zstrm, Z_NO_FLUSH);
         if(ret < 0) {
          uerror(" Error %d inflate (%s)", ret, decode_zlib_err(ret));
          (void)inflateEnd(&zstrm);
           return ret;
         }
         inflatedBytes = CHUNK_SZ - zstrm.avail_out;

         if(inflatedBytes == 0) {
              unotice("\n Unable to decompress data - truncated");
              break;
         }
     totalBytesIn += zstrm.total_in;
     decompByteCounter += inflatedBytes;

     memcpy(dstBuf + savedByteCntr, out, inflatedBytes);
     savedByteCntr = decompByteCounter;
   }

   // Reset inflater for additional input
   ret = inflateReset(&zstrm);
   if(ret == Z_STREAM_ERROR){
      uerror(" Error %d inflateReset (%s)", ret, decode_zlib_err(ret));
      (void)inflateEnd(&zstrm);
       return ret;
   }
  }

if(isLastBlk){
 ret = inflateEnd(&zstrm);
 if(ret < 0) {
   uerror("Fail inflateEnd %d [%s] ", ret, decode_zlib_err(ret));
   return (ret);
 }
}

  *outLen = decompByteCounter;
   return 0;
}

Заранее спасибо за поддержку.

Спасибо, Сатья.

1 ответ

Решение

Вы делаете ошибку при использовании вашего inflateData() рутина.

Во-первых, использование статической переменной таким образом - ужасная идея. Если вы позвоните inflateData() дважды с isFirstBlk правда без промежуточного вызова с isLastBlk Значение true, тогда вы сотрете ссылку на первый набор выделений, что приведет к утечке памяти.

Чтобы избежать такого рода ошибок, вы должны следить за тем, zstrm инициализируется или нет, и отклонить любую попытку инициализировать уже инициализированный поток. Еще лучше было бы даже не иметь isFirstBlkи просто инициализировать zstrm на первый звонок и на любой звонок, который следует сразу за звонком с isLastBlk правда.

Таким образом, вы либо делаете вышеуказанное, звоните дважды с isFirstBlk истина или не удается позвонить с isLastBlk правда.

Другие вопросы по тегам