zlib inflateReset 导致内存泄漏(不是)
zlib inflateReset causes memory leak (not)
我目前正在处理以下要求。
这是要求:在服务器端,一个大文件被分成 4000 字节的块(帧)。每个块依次压缩(使用 zlib)并发送到客户端进程。例如,如果一个文件的大小为 12000 字节,则将其分成 3 个块。
以上文件将有 3 个块 => Block-0、Block-1、Block-2
收到后,客户端解压缩每个块(或帧)并写入 heap.When 上分配的缓冲区,客户端收到与整个文件对应的所有块,然后是结果文件的未压缩版本已写入磁盘。
我编写了一个例程 inflateData,它根据接收到的块# 执行以下操作:
收到第一个块时,
- 膨胀初始化
- 充气
- 充气复位
当收到中间块时,
- 充气
- 充气复位
当收到最后一个块时,
- 充气
- 膨胀结束
通过上述例程,块的解压缩按预期进行。但我面临的问题是它会消耗大量内存,有时整个系统都会变慢。当使用 valgrind 检查时,内存泄漏通过 inflateInit2_ 报告。这会导致系统资源耗尽。
==30359== 57,312 bytes in 6 blocks are possibly lost in loss record 64 of 67
==30359== at 0x4A069EE: malloc (vg_replace_malloc.c:270)
==30359== by 0x3E57808F1E: inflateInit2_ (in /lib64/libz.so.1.2.3)
==30359== by 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, '[=10=]', 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;
}
在此先感谢您的支持。
谢谢,
沙迪亚
您在使用 inflateData()
例程时出错。
首先,以这种方式使用静态变量是一个糟糕的想法。如果您使用 isFirstBlk
true 调用 inflateData()
两次,而没有使用 isLastBlk
true 进行中间调用,那么您将清除对第一组分配的引用,从而导致内存泄漏。
为避免此类错误,您应该跟踪 zstrm
是否已初始化,并拒绝任何初始化已初始化流的尝试。更好的办法是甚至没有 isFirstBlk
,并在第一次调用时以及在 isLastBlk
true.
调用后立即初始化 zstrm
所以你要么在做上面的事情,用 isFirstBlk
true 调用两次,要么用 isLastBlk
true 调用失败。
我目前正在处理以下要求。 这是要求:在服务器端,一个大文件被分成 4000 字节的块(帧)。每个块依次压缩(使用 zlib)并发送到客户端进程。例如,如果一个文件的大小为 12000 字节,则将其分成 3 个块。
以上文件将有 3 个块 => Block-0、Block-1、Block-2
收到后,客户端解压缩每个块(或帧)并写入 heap.When 上分配的缓冲区,客户端收到与整个文件对应的所有块,然后是结果文件的未压缩版本已写入磁盘。
我编写了一个例程 inflateData,它根据接收到的块# 执行以下操作:
收到第一个块时, - 膨胀初始化 - 充气 - 充气复位 当收到中间块时, - 充气 - 充气复位 当收到最后一个块时, - 充气 - 膨胀结束
通过上述例程,块的解压缩按预期进行。但我面临的问题是它会消耗大量内存,有时整个系统都会变慢。当使用 valgrind 检查时,内存泄漏通过 inflateInit2_ 报告。这会导致系统资源耗尽。
==30359== 57,312 bytes in 6 blocks are possibly lost in loss record 64 of 67
==30359== at 0x4A069EE: malloc (vg_replace_malloc.c:270)
==30359== by 0x3E57808F1E: inflateInit2_ (in /lib64/libz.so.1.2.3)
==30359== by 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, '[=10=]', 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;
}
在此先感谢您的支持。
谢谢, 沙迪亚
您在使用 inflateData()
例程时出错。
首先,以这种方式使用静态变量是一个糟糕的想法。如果您使用 isFirstBlk
true 调用 inflateData()
两次,而没有使用 isLastBlk
true 进行中间调用,那么您将清除对第一组分配的引用,从而导致内存泄漏。
为避免此类错误,您应该跟踪 zstrm
是否已初始化,并拒绝任何初始化已初始化流的尝试。更好的办法是甚至没有 isFirstBlk
,并在第一次调用时以及在 isLastBlk
true.
zstrm
所以你要么在做上面的事情,用 isFirstBlk
true 调用两次,要么用 isLastBlk
true 调用失败。