Protobuf ParseFromZeroCopyStream在重复字段时会占用大量内存

时间:2017-07-27 05:11:48

标签: c++11 protocol-buffers

使用ParseFromZeroCopyStream加载写入大缓冲区的文件时,我遇到了内存使用率高的问题。此外,下面的代码片段使用60Gb ++的RAM但由于系统在达到RAM限制后冻结而失败。

仅供参考,我使用protobuf作为DLL。

scene.proto

syntax = "proto3";

package Recipe;

option cc_enable_arenas = true;

message Scene
{
    repeated int32 image_data = 1 [packed=true];
}

source.cpp

#include <iostream>
#include <fstream>
#include <ostream>
#include <istream>
#include <string>
#include <cstdint>
#include "Scene.pb.h"
#include <google\protobuf\io\zero_copy_stream_impl.h>
#include <google\protobuf\io\gzip_stream.h>
#include <google\protobuf\arena.h>

int const _MIN = 0;
int const _MAX = 255;
unsigned int const _SIZE = 1280000000;
//unsigned int const _SIZE = 2000;
unsigned int const _COMPRESSION_LEVEL = 6;


void randWithinUnsignedCharSize(uint8_t * buffer, unsigned int size)
{
    for (size_t i = 0; i < size; ++i)
    {
        buffer[i] = i;
    }
}

using namespace google::protobuf::io;

int main()
{
    GOOGLE_PROTOBUF_VERIFY_VERSION;

    {
        google::protobuf::Arena arena;

        Recipe::Scene * scene = google::protobuf::Arena::CreateMessage<Recipe::Scene>(&arena);
        uint8_t * imageData = new uint8_t[_SIZE];
        randWithinUnsignedCharSize(imageData, _SIZE);
        scene->mutable_image_data()->Resize(_SIZE, 0);
        for (size_t i = 0; i < _SIZE; i++)
        {
            scene->set_image_data(i, imageData[i]);
        }
        std::cout << "done saving data to repeated field.\n";
        {
            std::fstream output("data.txt", std::ios::out | std::ios::trunc | std::ios::binary);
            OstreamOutputStream outputFileStream(&output);
            GzipOutputStream::Options options;
            options.format = GzipOutputStream::GZIP;
            options.compression_level = _COMPRESSION_LEVEL;

            GzipOutputStream gzipOutputStream(&outputFileStream, options);

            if (!scene->SerializeToZeroCopyStream(&gzipOutputStream)) {
                std::cerr << "Failed to write scene." << std::endl;
                return -1;
            }
        }
        delete[] imageData;
    }
    std::cout << "Finish serializing into data.txt\n";
    {
        google::protobuf::Arena arena1;
        Recipe::Scene * scene1 = google::protobuf::Arena::CreateMessage<Recipe::Scene>(&arena1);
        {
            std::fstream input("data.txt", std::ios::in | std::ios::binary);
            IstreamInputStream inputFileStream(&input);
            GzipInputStream gzipInputStream(&inputFileStream);
            if (!scene1->ParseFromZeroCopyStream(&gzipInputStream)) {
                std::cerr << "Failed to parse scene." << std::endl;
                return -1;
            }
        }

        std::cout << "scene1->imagedata_size() " << scene1->image_data_size() << std::endl;
    }

    google::protobuf::ShutdownProtobufLibrary();
    return 0;
}

0 个答案:

没有答案