首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >RcppArmadillo:内存使用问题

RcppArmadillo:内存使用问题
EN

Stack Overflow用户
提问于 2015-07-15 19:15:56
回答 1查看 1.2K关注 0票数 5

我开始使用Rcpp了。我非常喜欢它。我对编程相当陌生。我有一个关于内存使用的问题。以下是一个可重复的问题:

代码语言:javascript
复制
library(RcppArmadillo)
library(inline)
code <- "
  Rcpp::NumericVector input_(input);
  arma::cube disturb(input_.begin(), 2, 2, 50000000, false);
  return wrap(2);
"
Test <- cxxfunction(signature(input = "numeric"), plugin = "RcppArmadillo", body = code)
input <- array(rnorm(2 * 2 * 50000000), dim = c(2, 2, 50000000))
Test(input)

我的理解是,在上面的问题中,唯一的内存使用是当我为R中的变量输入分配数组时,所以我应该只使用1.6GB (2*2*50*8 = 1600)。当我转到Rcpp时,我使用input_对象初始化变量,它是一个指针。因此,这不应该使用任何额外的内存。然后,当我初始化变量扰动时,我还使用一个指针并设置copy_aux = FALSE。所以我不应该用任何记忆。因此,如果我的理解是正确的,那么在运行代码时,我应该只使用1.6GB。这是正确的吗?

但是,当我运行代码时,内存使用量(从Ubuntu中的系统监视器判断)跃升到10 gb以上(从大约1GB),然后下降到大约4GB。我不明白怎么回事。我是不是用错了Rcpp?

谢谢你的帮助。非常感谢。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-07-17 10:09:21

新版本的Armadillo (5.300)编辑

在对StackOverflow进行了最初的问答之后,康拉德·桑德森和我就这个问题进行了一些电子邮件讨论。通过设计,arma::cube对象为cube的每个切片(第三维度)创建一个arma::mat。这是在创建cube期间完成的,即使数据是从现有内存中复制的(如原来的问题)。由于这并不总是需要的,所以我建议应该有一个选项来禁用片的矩阵预分配。截至目前版本的Armadillo (5.300.4),现在有了。这可以从CRAN安装。

示例代码:

代码语言:javascript
复制
library(RcppArmadillo)
library(inline)
code <- "
  Rcpp::NumericVector input_(input);
  arma::cube disturb(input_.begin(), 2, 2, 50000000, false, true, false);
  return wrap(2);
"
Test <- cxxfunction(signature(input = "numeric"), plugin = "RcppArmadillo", body = code)
input <- array(rnorm(2 * 2 * 50000000), dim = c(2, 2, 50000000))
Test(input)

这里的关键是现在使用cube调用arma::cube disturb(input.begin(), 2, 2, 50000000, false, true, false);构造函数。这里的最后一个false是新的prealloc_mat参数,它决定是否预先分配矩阵。slice方法在没有预先分配矩阵的cube上仍能很好地工作--矩阵将按需分配。但是,如果您直接访问一个mat_ptrscube成员,它将被NULL指针填充。该帮助也已得到更新。

感谢康拉德·桑德森如此迅速地提供了这一额外的选择,并感谢德克·埃德德尔贝特尔在Rcpp和RcppArmadillo上所做的一切工作!

原始答案

有点怪怪的。我尝试了一系列不同的数组大小,问题只发生在三维比其他2大得多的数组中。

代码语言:javascript
复制
library("RcppArmadillo")
library("inline")
code <- "
Rcpp::NumericVector input_(input);
IntegerVector dim = input_.attr(\"dim\");
arma::cube disturb(input_.begin(), dim[0], dim[1], dim[2], false);
disturb[0, 0, 0] = 45;
return wrap(2);
"
Test <- cxxfunction(signature(input = "numeric"), plugin = "RcppArmadillo", body = code)
input <- array(0, c(1e7, 2, 2))
Test(input)
# no change in memory usage

dim(input) <- c(2, 1e7, 2)
gc()
Test(input)
# no change in memory usage

dim(input) <- c(2, 2, 1e7)
gc()
Test(input)
# spike in memory usage

dim(input) <- c(20, 2, 1e6)
gc()
Test(input)
# no change in memory usage

这说明了Aramadillo库的实现方式(或者可能是RcppArmadillo)。这显然不是你做错的事。

注意,我已经对数据进行了一些修改(将第一个元素设置为45),您可以确认在每一种情况下,数据都是修改好的,这意味着没有副本。

现在,我建议,如果可能的话,组织你的3d数组,这样最大的维度不是第三个。

编辑了,在做了更多的挖掘之后,看起来好像在创建arma::cube期间是对RAM的分配。在Cube_meat.hpp中,在create_mat方法中,有以下代码:

代码语言:javascript
复制
if(n_slices <= Cube_prealloc::mat_ptrs_size)
  {
  access::rw(mat_ptrs) = const_cast< const Mat<eT>** >(mat_ptrs_local);
  }
else
  {
  access::rw(mat_ptrs) = new(std::nothrow) const Mat<eT>*[n_slices];

  arma_check_bad_alloc( (mat_ptrs == 0), "Cube::create_mat(): out of memory" );
  }
}

Cube_prealloc::mat_ptrs_size似乎是4,所以对于任何有超过4片的数组来说,这实际上都是一个问题。

我发了一个github问题

然而,EDIT2绝对是底层Armadillo代码的一个问题。下面是一个完全不使用Rcpp的可复制示例。这是linux专用的,它使用如何在运行时在c++中获得内存使用量?中的代码提取正在运行的进程的当前内存使用情况。

代码语言:javascript
复制
#include <iostream>
#include <armadillo>
#include <unistd.h>
#include <ios>
#include <fstream>
#include <string>

//////////////////////////////////////////////////////////////////////////////
//
// process_mem_usage(double &, double &) - takes two doubles by reference,
// attempts to read the system-dependent data for a process' virtual memory
// size and resident set size, and return the results in KB.
//
// On failure, returns 0.0, 0.0

void process_mem_usage(double& vm_usage, double& resident_set)
{
   using std::ios_base;
   using std::ifstream;
   using std::string;

   vm_usage     = 0.0;
   resident_set = 0.0;

   // 'file' stat seems to give the most reliable results
   //
   ifstream stat_stream("/proc/self/stat",ios_base::in);

   // dummy vars for leading entries in stat that we don't care about
   //
   string pid, comm, state, ppid, pgrp, session, tty_nr;
   string tpgid, flags, minflt, cminflt, majflt, cmajflt;
   string utime, stime, cutime, cstime, priority, nice;
   string O, itrealvalue, starttime;

   // the two fields we want
   //
   unsigned long vsize;
   long rss;

   stat_stream >> pid >> comm >> state >> ppid >> pgrp >> session >> tty_nr
               >> tpgid >> flags >> minflt >> cminflt >> majflt >> cmajflt
               >> utime >> stime >> cutime >> cstime >> priority >> nice
               >> O >> itrealvalue >> starttime >> vsize >> rss; // don't care about the rest

   stat_stream.close();

   long page_size_kb = sysconf(_SC_PAGE_SIZE) / 1024; // in case x86-64 is configured to use 2MB pages
   vm_usage     = vsize / 1024.0;
   resident_set = rss * page_size_kb;
}

using namespace std;
using namespace arma;

void test_cube(double* numvec, int dim1, int dim2, int dim3) {
  double vm, rss;

  cout << "Press enter to continue";
  cin.get();

  process_mem_usage(vm, rss);
  cout << "Before:- VM: " << vm << "; RSS: " << rss << endl;

  cout << "cube c1(numvec, " << dim1 << ", " << dim2 << ", " << dim3 << ", false)" << endl;
  cube c1(numvec, dim1, dim2, dim3, false);

  process_mem_usage(vm, rss);
  cout << "After:-  VM: " << vm << "; RSS: " << rss << endl << endl;
}

int
main(int argc, char** argv)
  {
  double* numvec = new double[40000000];

  test_cube(numvec, 10000000, 2, 2);
  test_cube(numvec, 2, 10000000, 2);
  test_cube(numvec, 2, 2, 1000000);
  test_cube(numvec, 2, 2, 2000000);
  test_cube(numvec, 4, 2, 2000000);
  test_cube(numvec, 2, 4, 2000000);
  test_cube(numvec, 4, 4, 2000000);
  test_cube(numvec, 2, 2, 10000000);

  cout << "Press enter to finish";
  cin.get();

  return 0;
  }

根据上面的代码编辑3,为多维数据集的每个切片创建一个arma::mat。在我的64位机器上,这会为每个片造成184字节的开销.对于5e7片的多维数据集,这等于8.6GiB的开销,尽管底层的数字数据只占1.5 GiB。我给康拉德·桑德森发了邮件,询问这是Armadillo工作方式的基础还是可以改变的,但现在看来,如果可能的话,您肯定希望您的slice维度(第三个维度)是最小的。值得注意的是,这也适用于all cube,而不仅仅是那些从现有内存中创建的。使用arma::cube(dim1, dim2, dim3)构造函数会导致相同的内存使用。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31439134

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档