iOS官方compression_encode_buffer为何无法处理短LZ4压缩数据?
iOS官方
compression_encode_buffer无法处理短数据的原因分析 测试场景说明
测试使用的短数据:
data {length = 17, bytes = 0x00000000020000000100000000ffe2ff61}
两种压缩实现对比
1. iOS官方compression_encode_buffer实现
代码实现:
@implementation NSData (lz4) - (NSData *)pluLZ4 { uint8_t dstBuffer[self.length]; memset(dstBuffer, 0, self.length); if (@available(iOS 9.0, *)) { size_t compressResultLength = compression_encode_buffer(dstBuffer, self.length, [self bytes], self.length, NULL, COMPRESSION_LZ4_RAW); if (compressResultLength > 0) { NSData *dataAfterCompress = [NSData dataWithBytes:dstBuffer length:compressResultLength]; return dataAfterCompress; } else { } } else { return self; } return nil; } @end
执行结果:compressResultLength返回0,目标缓冲区为空,压缩失败。
2. LZ4官方实现
代码实现:
@implementation NSData (lz4) - (NSData *)compressLZ4 { int res = 0; int size = LZ4_compressBound((int) self.length); char *buffer = (char *)malloc((size_t) size); res = LZ4_compress_default(self.bytes, buffer, (int) self.length, size); if (res < 0) { free(buffer); return nil; } return [[NSData alloc] initWithBytesNoCopy:buffer length:res freeWhenDone:YES]; } @end
执行结果:成功生成压缩数据,结果为:
data {length = 19, bytes = 0xf00200000000020000000100000000ffe2ff61}
核心原因解析
目标缓冲区空间不足
LZ4原始压缩模式处理短数据时,生成的压缩结果可能比原数据更长(比如本次测试中17字节数据压缩后变为19字节)。你的代码将目标缓冲区大小设为self.length,刚好等于原数据长度,无法容纳更长的压缩结果,导致compression_encode_buffer直接返回0表示失败。内部策略差异
Apple实现的compression_encode_buffer包含额外判断逻辑:当预测到压缩结果无法放入指定缓冲区(或压缩后数据不小于原数据)时,直接返回0;而官方LZ4库的LZ4_compress_default会严格遵循LZ4设计规范,确保所有输入数据都能被压缩,哪怕结果比原数据大。可选参数缺失影响
你为compression_encode_buffer传入的第五个临时工作缓冲区参数为NULL,虽然该参数是可选的,但在处理短数据这类边缘场景时,可能会影响压缩函数的正常执行流程。
修复建议
- 调整目标缓冲区大小:参考官方LZ4实现,用
LZ4_compressBound计算所需的最大缓冲区空间,或直接预留self.length * 1.2这类保守空间。 - 优化返回逻辑:当
compression_encode_buffer返回0时,直接返回原数据,避免返回nil导致业务异常。
内容的提问来源于stack exchange,提问作者Gump Gump
相关产品推荐
相关产品推荐

