【问题标题】:Why do R functions use more memory the first time they are run?为什么 R 函数在第一次运行时会使用更多内存?
【发布时间】:2020-09-29 13:17:53
【问题描述】:

我一直在比较矢量化 R 代码和非矢量化 R 代码,并注意到函数在第一次运行时似乎使用更多内存。这是一个可重现的示例:

library(bench)

squares <- function(x)
{
        y <- x
        for(i in seq_along(x))
        {
            y[i] <- x[i]*x[i]
        }
        return(y)
}

x <- 1:100
bm <- mark(x^2, squares(x))
bm

第一次运行时,squares(x) 使用的内存(mem_alloc 列)比 x^2 多:

> bm
# A tibble: 2 x 13
  expression    min  median `itr/sec` mem_alloc `gc/sec` n_itr  n_gc total_time
  <bch:expr> <bch:> <bch:t>     <dbl> <bch:byt>    <dbl> <int> <dbl>   <bch:tm>
1 x^2             0 558.1ns  1387977.    1.27KB        0 10000     0     7.21ms
2 squares(x) 12.4µs  14.2µs    64885.    4.15MB        0 10000     0   154.12ms
# … with 4 more variables: result <list>, memory <list>, time <list>, gc <list>

但是如果我再次运行代码,我会得到非常不同的结果:

> bm <- mark(x^2, squares(x))
> bm
# A tibble: 2 x 13
  expression    min  median `itr/sec` mem_alloc `gc/sec` n_itr  n_gc total_time
  <bch:expr> <bch:> <bch:t>     <dbl> <bch:byt>    <dbl> <int> <dbl>   <bch:tm>
1 x^2             0 490.1ns  1430864.      848B     0    10000     0     6.99ms
2 squares(x) 12.9µs  16.4µs    57321.      448B     5.73  9999     1   174.44ms
# … with 4 more variables: result <list>, memory <list>, time <list>, gc <list>

如果我再次运行基准测试,我会得到与第二次相同的结果。

如果当我第一次启动 R 时,我在基准测试之前运行函数,我会得到以下结果:

> 1^2
[1] 1
> squares(1)
[1] 1
> bm <- mark(x^2, squares(x))
> bm
# A tibble: 2 x 13
  expression    min  median `itr/sec` mem_alloc `gc/sec` n_itr  n_gc total_time
  <bch:expr> <bch:> <bch:t>     <dbl> <bch:byt>    <dbl> <int> <dbl>   <bch:tm>
1 x^2             0 977.1ns   993503.    1.27KB        0 10000     0     10.1ms
2 squares(x) 12.8µs  14.5µs    63713.      448B        0 10000     0      157ms
# … with 4 more variables: result <list>, memory <list>, time <list>, gc <list>

请注意,squares(x) 的内存使用率与第二次运行时一样低,但x^2 的使用率却没有。相反,如果我在第一个基准测试之前运行x^2,则用于x^2 的内存将下降到848B

这是因为用于 R 的即时编译的内存在函数第一次运行时包含在内存分析中吗?如果是这样,为什么x^2 会受到影响-^ 运算符不是已经编译为字节码了吗?我是否误解了 R 中的内存分析功能?还是这里发生了其他事情?

【问题讨论】:

  • ^ 未编译为字节码。它是一个原始函数(意味着它是编译的 C 代码)。无论如何,我建议您关闭 JIT 字节码编译并再次进行基准测试。这应该可以回答您的一些问题。
  • @Roland:非常感谢您的建议 - 关闭 JIT 编译很有启发性!我已将结果发布为答案。

标签: r runtime-compilation


【解决方案1】:

根据 Roland 的评论(谢谢!),我尝试关闭 JIT 编译。结果表明,函数第一次运行时额外的内存使用确实是由于编译:

library(compiler)
library(bench)
enableJIT(0) # Turn of JIT compilation

squares <- function(x)
{
        y <- x
        for(i in seq_along(x))
        {
            y[i] <- x[i]*x[i]
        }
        return(y)
}

结果如下:

> x <- 1:100
> bm <- mark(x^2, squares(x))
> bm
# A tibble: 2 x 13
  expression    min  median `itr/sec` mem_alloc `gc/sec` n_itr  n_gc total_time
  <bch:expr> <bch:> <bch:t>     <dbl> <bch:byt>    <dbl> <int> <dbl>   <bch:tm>
1 x^2             0 490.1ns  1205874.    1.27KB      0   10000     0     8.29ms
2 squares(x) 81.3µs  96.9µs    10428.      448B     62.7  4488    27   430.39ms
# … with 4 more variables: result <list>, memory <list>, time <list>, gc <list>
> 
> # A second run:
> bm <- mark(x^2, squares(x))
> bm
# A tibble: 2 x 13
  expression    min  median `itr/sec` mem_alloc `gc/sec` n_itr  n_gc total_time
  <bch:expr> <bch:> <bch:t>     <dbl> <bch:byt>    <dbl> <int> <dbl>   <bch:tm>
1 x^2             0 559.1ns  1311094.      848B      0   10000     0     7.63ms
2 squares(x) 79.3µs  87.7µs    10749.      448B     80.0  4571    34   425.25ms
# … with 4 more variables: result <list>, memory <list>, time <list>, gc <list>

(正如预期的那样,未编译的函数速度较慢,尽管这不是实验的重点。)

此外,使用cmpfun 进行显式编译还可以消除第一次运行时多余的内存使用:

library(compiler)
squares <- cmpfun(squares)

产量

> x <- 1:100
> bm <- mark(x^2, squares(x))
> bm
# A tibble: 2 x 13
  expression    min  median `itr/sec` mem_alloc `gc/sec` n_itr  n_gc total_time
  <bch:expr> <bch:> <bch:t>     <dbl> <bch:byt>    <dbl> <int> <dbl>   <bch:tm>
1 x^2           1ns   560ns  1163023.    1.27KB        0 10000     0      8.6ms
2 squares(x) 11.1µs  13.5µs    71576.      448B        0 10000     0    139.7ms
# … with 4 more variables: result <list>, memory <list>, time <list>, gc <list>

第一次运行。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-08-09
    • 1970-01-01
    • 2020-01-02
    • 2023-03-17
    • 1970-01-01
    • 2015-01-01
    • 2022-01-20
    • 1970-01-01
    相关资源
    最近更新 更多