zlib, deflate: combien de mémoire allouer?

J’utilise zlib pour compresser un stream de données texte. Les données de texte sont présentées en morceaux et pour chaque morceau, la fonction deflate() est appelée, flush étant défini sur Z_NO_FLUSH . Une fois que tous les morceaux ont été récupérés, la fonction deflate() est appelée avec la valeur flush définie sur Z_FINISH .

Naturellement, deflate() ne produit pas de sortie compressée à chaque appel. Il accumule en interne les données pour atteindre un taux de compression élevé. Et c’est bon! Chaque fois que deflate() produit une sortie compressée, cette sortie est ajoutée à un champ de firebase database – un processus lent.

Cependant, une fois que deflate() produit des données compressées, celles-ci peuvent ne pas entrer dans le tampon de sortie fourni, deflate_out . Par conséquent, plusieurs appels à deflate() sont requirejs. Et c’est ce que je veux éviter:

Existe-t-il un moyen de faire en deflate_out que deflate_out toujours suffisamment grand pour que deflate() puisse y stocker toutes les données compressées, chaque fois qu’il décide de produire une sortie?

Remarques:

  • La taille totale des données non compressées n’est pas connue à l’avance. Comme mentionné ci-dessus, les données non compressées sont fournies en morceaux, et les données compressées sont ajoutées à un champ de firebase database, également en morceaux.

  • Dans le fichier d’ zconf.h j’ai trouvé le commentaire suivant. Est-ce que c’est peut-être ce que je cherche? C’est-à-dire (1 << (windowBits+2)) + (1 << (memLevel+9)) la taille maximale en octets des données compressées que deflate() peut produire?

     /* 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. */ 

deflateBound () n’est utile que si vous effectuez toute la compression en une seule étape ou si vous forcez la commande deflate à compresser toutes les données d’entrée actuellement disponibles et à émettre des données compressées pour toutes ces entrées. Vous feriez cela avec un paramètre de vidage tel que Z_BLOCK, Z_PARTIAL_FLUSH, etc.

Si vous souhaitez utiliser Z_NO_FLUSH, il devient beaucoup plus difficile et inefficace de tenter de prévoir le plus grand nombre de sorties que deflate () pourrait émettre lors du prochain appel. Vous ne savez pas quelle quantité d’entrée a été consommée au moment de l’émission de la dernière rafale de données compressées; vous devez donc en supposer presque rien, la taille de la mémoire tampon augmentant inutilement. Quoi que vous essayiez d’estimer, vous ferez beaucoup de mallocs ou de reallocs inutiles sans raison valable, ce qui est inefficace.

Il ne sert à rien d’éviter d’appeler deflate () pour plus de sortie. Si vous bouclez simplement sur deflate () jusqu’à ce qu’il n’y ait plus de sortie pour vous, vous pouvez alors utiliser un tampon de sortie fixe mallocalisé une fois. C’est ainsi que les interfaces deflate () et inflate () ont été conçues pour être utilisées. Vous pouvez consulter http://zlib.net/zlib_how.html pour obtenir un exemple bien documenté sur l’utilisation de l’interface.

À propos, il existe une fonction deflatePending () dans la dernière version de zlib (1.2.6) qui vous permet de connaître le nombre de sorties attendues par deflate ().

Tout en regardant les sources pour un indice, je suis tombé sur

 /* ========================================================================= * 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; ... 

traquer l’utilisation de void flush_pending () tout au long de deflate () montre qu’une limite supérieure sur la mémoire tampon de sortie nécessaire au milieu du stream est

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

la première partie comptabilise les données encore dans le canal des appels précédents à deflate (), la deuxième partie comptabilise les données non encore traitées de longueur avail_in.