zlib, deflate: сколько памяти выделить? - PullRequest
13 голосов
/ 18 января 2012

Я использую zlib для сжатия потока текстовых данных. Текстовые данные поступают в виде фрагментов, и для каждого фрагмента вызывается deflate(), а для сброса устанавливается значение Z_NO_FLUSH. Как только все фрагменты будут получены, вызывается deflate() с установленным значением сброса Z_FINISH.

Естественно, deflate() не производит сжатый вывод при каждом вызове. Он накапливает данные для достижения высокой степени сжатия. И это нормально! Каждый раз, когда deflate() производит сжатый вывод, этот вывод добавляется в поле базы данных - медленный процесс.

Однако, когда deflate() создает сжатые данные, эти данные могут не помещаться в предоставленный выходной буфер, deflate_out. Поэтому требуется несколько звонков на deflate(). И вот чего я хочу избежать:

Есть ли способ сделать deflate_out всегда достаточно большим, чтобы deflate() мог хранить в нем все сжатые данные, каждый раз, когда он решает произвести вывод?

Примечания:

  • Общий размер несжатых данных не заранее известен. Как упоминалось выше, несжатые данные поступают в виде фрагментов, а сжатые данные добавляются в поле базы данных, также в виде фрагментов.

  • Во включаемом файле zconf.h Я нашел следующий комментарий. Это то, что я ищу? То есть (1 << (windowBits+2)) + (1 << (memLevel+9)) - это максимальный размер сжатых данных в байтах, который deflate() может выдать?

    /* The memory requirements for deflate are (in bytes):
                (1 << (windowBits+2)) +  (1 << (memLevel+9))
     that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
     plus a few kilobytes for small objects. For example, if you want to reduce
     the default memory requirements from 256K to 128K, compile with
         make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
     Of course this will generally degrade compression (there's no free lunch).
    
       The memory requirements for inflate are (in bytes) 1 << windowBits
     that is, 32K for windowBits=15 (default value) plus a few kilobytes
     for small objects.
    */
    

Ответы [ 2 ]

7 голосов
/ 31 января 2012

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

Если вы хотите использовать Z_NO_FLUSH, то становится гораздо труднее и неэффективно пытаться предсказать наибольшее количество выходных данных, которые deflate () может испустить при следующем вызове. Вы не знаете, сколько входных данных было использовано во время последнего пакета сжатых данных, поэтому вы должны предположить, что почти ничего из этого не произошло, при этом размер буфера увеличивался без необходимости. Однако вы пытаетесь оценить максимальную производительность, вы будете делать много ненужных malloc или reallocs без веской причины, которая неэффективна.

Нет смысла избегать вызова deflate () для большего вывода. Если вы просто зацикливаетесь на deflate () до тех пор, пока у вас больше не будет выходных данных, то вы можете использовать фиксированный выходной буфер, заблокированный один раз. Именно так был разработан интерфейс deflate () и inflate (). Вы можете посмотреть на http://zlib.net/zlib_how.html хорошо документированный пример использования интерфейса.

Кстати, в последней версии zlib (1.2.6) есть функция deflatePending (), которая позволяет узнать, сколько выходных данных ожидает от deflate ().

2 голосов
/ 18 января 2012

Просматривая источники для подсказки, я упал

/* =========================================================================
 * Flush as much pending output as possible. All deflate() output goes
 * through this function so some applications may wish to modify it
 * to avoid allocating a large strm->next_out buffer and copying into it.
 * (See also read_buf()).
 */
local void flush_pending(strm)
    z_streamp strm;
{
    unsigned len = strm->state->pending;
...

, отслеживая использование void flush_pending () по всему deflate (), показывает, что верхняя граница необходимого выходного буфера в серединепотока -

strm->state->pending + deflateBound(strm, strm->avail_in)

первая часть учитывает данные, все еще находящиеся в канале от предыдущих вызовов deflate (), вторая часть учитывает еще не обработанные данные длины длины_в

...