提升二进制档案 - 减小尺寸

时间:2017-08-22 01:06:25

标签: c++ serialization boost archive

我正在尝试减少C ++中boost存档的内存大小。

我发现的一个问题是,Boost的二进制存档默认为任何int使用4个字节,无论其大小如何。出于这个原因,我得到一个空的boost二进制存档需要62个字节,而空文本存档需要40个(文本表示空文本存档:22 serialization::archive 14 0 0 1 0 0 0 0 0)。

有没有办法更改int的默认行为?

否则,除了使用make_array作为向量之外,还有其他方法可以优化二进制存档的大小吗?

2 个答案:

答案 0 :(得分:1)

  1.   

    问。 我正在尝试减少C ++中boost档案的内存大小。

    请参阅Boost C++ Serialization overhead

  2.   

    问。 我发现的一个问题是Boost的二进制存档默认为任何int使用4个字节,无论其大小如何。

    那是因为它是一个序列化库,而不是压缩库

  3.   

    问。 出于这个原因,我得到一个空的boost二进制存档需要62个字节,而空文本存档需要40个(文本表示空文本存档:22序列化: :archive 14 0 0 1 0 0 0 0 0)。

    使用存档标志:例如来自Boost Serialization : How To Predict The Size Of The Serialized Result?

      
        
    • 调整内容(boost :: archive :: no_codecvt,boost :: archive :: no_header,disable tracking等。)
    •   
  4.   

    问。 有没有办法更改整数的默认行为?

    没有。但有BOOST_IS_BITWISE_SERIALIZABLE(T)(例如,参见Boost serialization bitwise serializability的示例和解释)。

  5.   

    问。 否则,除了对向量使用make_array之外,还有其他方法可以优化二进制存档的大小吗?

    使用make_arrayvector<int>无效:

    <强> Live On Coliru

    #include <boost/archive/binary_oarchive.hpp>
    #include <boost/serialization/vector.hpp>
    #include <sstream>
    #include <iostream>
    
    static auto const flags = boost::archive::no_header | boost::archive::no_tracking;
    
    template <typename T>
    std::string direct(T const& v) {
        std::ostringstream oss;
        {
            boost::archive::binary_oarchive oa(oss, flags);
            oa << v;
        }
        return oss.str();
    }
    
    template <typename T>
    std::string as_pod_array(T const& v) {
        std::ostringstream oss;
        {
            boost::archive::binary_oarchive oa(oss, flags);
            oa << v.size() << boost::serialization::make_array(v.data(), v.size());
        }
        return oss.str();
    }
    
    int main() {
        std::vector<int> i(100);
        std::cout << "direct: "       << direct(i).size() << "\n";
        std::cout << "as_pod_array: " << as_pod_array(i).size() << "\n";
    }
    

    打印

    direct: 408
    as_pod_array: 408
    
  6. 压缩

    最直接的优化方法是压缩生成的流(另请参阅添加的基准here)。

    除此之外,您必须覆盖默认序列化并应用您自己的压缩(可能是一个简单的游程编码,霍夫曼编码或更具域特性的东西)。

    演示

    <强> Live On Coliru

    #include <boost/archive/binary_oarchive.hpp>
    #include <boost/serialization/vector.hpp>
    #include <sstream>
    #include <iostream>
    #include <boost/iostreams/filter/bzip2.hpp>
    #include <boost/iostreams/filtering_stream.hpp>
    #include <boost/iostreams/device/back_inserter.hpp>
    #include <boost/iostreams/copy.hpp>
    
    static auto const flags = boost::archive::no_header | boost::archive::no_tracking;
    
    template <typename T>
    size_t archive_size(T const& v)
    {
        std::stringstream ss;
        {
            boost::archive::binary_oarchive oa(ss, flags);
            oa << v;
        }
    
        std::vector<char> compressed;
        {
            boost::iostreams::filtering_ostream fos;
            fos.push(boost::iostreams::bzip2_compressor());
            fos.push(boost::iostreams::back_inserter(compressed));
    
            boost::iostreams::copy(ss, fos);
        }
    
        return compressed.size();
    }
    
    int main() {
        std::vector<int> i(100);
        std::cout << "bzip2: " << archive_size(i) << "\n";
    }
    

    打印

    bzip2: 47
    

    压缩率约为11%(如果删除存档标志,则为~19%)。

答案 1 :(得分:0)

正如Alexey所说,在Boost中你必须使用较小的成员变量。唯一可以做得更好的序列化是AFAIK,Google Protocol Buffers和ASN.1 PER。

GPB使用可变长度整数来使用适合于传输值的多个字节。

ASN.1 PER以不同的方式进行;在ASN.1方案中,您可以定义有效的值范围。因此,如果声明一个int字段的有效范围在0到15之间,它将只使用4位。 uPER更进一步;它没有将字段的位与字节边界对齐,从而节省了更多的位。 uPER是3G,4G在无线电链路上使用的,可以节省大量带宽。

据我所知,大多数其他努力涉及使用ZIP或类似的后序列化压缩。对于大量数据来说很好,否则就是垃圾。