如何在使用 Apache Arrow C++ API 读取 CSV 时管理内存?

How to manage memory while reading CSV using Apache Arrow C++ API?

我不了解 C++ Arrow 中的内存管理 API。我使用 Arrow 1.0.0 并且正在读取 CSV 文件。 ReadArrowTableFromCSV 运行几次后,我的内存中充满了已分配的数据。我错过了什么吗?我怎样才能释放那段记忆?我没有在内存池中看到任何方法来清除所有分配的内存。代码清单如下。

void LoadCSVData::ReadArrowTableFromCSV( const std::string & filePath )
{
    auto tableReader = CreateTableReader( filePath );
    ReadArrowTableUsingReader( *tableReader );
}

std::shared_ptr<arrow::csv::TableReader> LoadCSVData::CreateTableReader( const std::string & filePath )
{
    arrow::MemoryPool* pool = arrow::default_memory_pool();
    auto tableReader = arrow::csv::TableReader::Make( pool, OpenCSVFile( filePath ),
                                                      *PrepareReadOptions(), *PrepareParseOptions(), *PrepareConvertOptions() );
    if ( !tableReader.ok() )
    {
        throw BadParametersException( std::string( "CSV file reader error: " ) + tableReader.status().ToString() );
    }
    return *tableReader;
}

void LoadCSVData::ReadArrowTableUsingReader( arrow::csv::TableReader & reader )
{
    auto table = reader.Read();
    if ( !table.ok() )
    {
        throw BadParametersException( std::string( "CSV file reader error: " ) + table.status().ToString() );
    }
    this->mArrowTable = *table;
}

std::unique_ptr<arrow::csv::ParseOptions> LoadCSVData::PrepareParseOptions()
{
    auto parseOptions = std::make_unique<arrow::csv::ParseOptions>( arrow::csv::ParseOptions::Defaults() );
    parseOptions->delimiter = mDelimiter;
    return parseOptions;
}

std::unique_ptr<arrow::csv::ReadOptions> LoadCSVData::PrepareReadOptions()
{
    auto readOptions = std::make_unique<arrow::csv::ReadOptions>( arrow::csv::ReadOptions::Defaults() );
    readOptions->skip_rows = mNumberOfHeaderRows;
    readOptions->block_size = 1 << 27;  // 128 MB
    readOptions->column_names.reserve( mTable->GetNumberOfColumns() );

    for ( auto & colName : mTable->GetColumnsOrder() )
    {
        readOptions->column_names.emplace_back( colName );
    }

    return readOptions;
}

std::unique_ptr<arrow::csv::ConvertOptions> LoadCSVData::PrepareConvertOptions() const
{
    auto convertOptions = std::make_unique<arrow::csv::ConvertOptions>( arrow::csv::ConvertOptions::Defaults() );
    for ( auto & col : mTable->GetColumsInfo() )
    {
        convertOptions->column_types[col.second.GetName()] = MyTypeToArrowDataType( col.second.GetType() );
    }
    convertOptions->strings_can_be_null = true;

    return convertOptions;
}

std::shared_ptr<arrow::io::ReadableFile> LoadCSVData::OpenCSVFile( const std::string & filePath )
{
    MTR_SCOPE_FUNC();
    auto inputFileResult = arrow::io::ReadableFile::Open( filePath );
    if ( !inputFileResult.ok() )
    {
        throw BadParametersException( std::string( "CSV file reader error: " ) + inputFileResult.status().ToString() );
    }
    return *inputFileResult;
}

Maciej,方法 TableReader::Read 应该 return shared_ptr<arrow::Table>arrow::Table 本身有许多指向最终包含数据的结构的共享指针。要释放数据,您需要确保销毁 arrow::Table 及其所有副本。这应该在 shared_ptr 超出范围时立即发生。但是,您似乎将 table 存储在此处的成员变量中(这是预料之中的,您可能希望在阅读后使用数据):

this->mArrowTable = *table;

现在您有了 arrow::Table 实例的第二个副本。您可以将 this->mArrowTable 重新分配给一个新的空白 table 或者您可以销毁任何 this 。当然,如果您正在制作 table 的任何其他副本,那么您将需要确保它们也超出范围。