首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >从R写入Excel时处理java.lang.OutOfMemoryError

从R写入Excel时处理java.lang.OutOfMemoryError
EN

Stack Overflow用户
提问于 2014-02-21 22:52:19
回答 6查看 67.9K关注 0票数 86

Excel包可用于从R读取和写入xlsx电子表格。不幸的是,即使对于中等大的电子表格,也可能发生java.lang.OutOfMemoryError。特别地,

对象错误(“RJavaTools”,“Ljava/lang/

;”,"invokeMethod",cl,:

java.lang.OutOfMemoryError:.jcall("RJavaTools","Ljava/lang/Object;","newInstance",.jfindClass(类),:

java.lang.OutOfMemoryError:超出GC开销限制

(其他相关的异常也是可能的,但比较少见。)

在阅读电子表格时,也提出了类似的问题。

Importing a big xlsx file into R?

与CSV相比,使用Excel电子表格作为数据存储介质的主要优点是,您可以在同一文件中存储多个工作表,因此这里我们考虑要写入的数据框列表,每个工作表一个数据框。此示例数据集包含40个数据框,每个框有两列,最多200k行。它被设计得足够大,但您可以通过更改n_sheetsn_rows来更改大小。

代码语言:javascript
复制
library(xlsx)
set.seed(19790801)
n_sheets <- 40
the_data <- replicate(
  n_sheets,
  {
    n_rows <- sample(2e5, 1)
    data.frame(
      x = runif(n_rows),
      y = sample(letters, n_rows, replace = TRUE)
    )
  },
  simplify = FALSE
)
names(the_data) <- paste("Sheet", seq_len(n_sheets))

将其写入文件的自然方法是使用createWorkbook创建一个工作簿,然后循环调用createSheetaddDataFrame的每个数据框。最后,可以使用saveWorkbook将工作簿写入文件。我已经向循环中添加了消息,以便更容易地看到它在哪里失败。

代码语言:javascript
复制
wb <- createWorkbook()  
for(i in seq_along(the_data))
{
  message("Creating sheet", i)
  sheet <- createSheet(wb, sheetName = names(the_data)[i])
  message("Adding data frame", i)
  addDataFrame(the_data[[i]], sheet)
}
saveWorkbook(wb, "test.xlsx")  

在具有8 8GB内存的机器上以64位运行此程序,它会在第一次运行addDataFrame时抛出GC overhead limit exceeded错误。

如何使用xlsx将大型数据集写入Excel电子表格

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2014-02-21 22:53:26

这是一个已知的问题:http://code.google.com/p/rexcel/issues/detail?id=33

虽然未解决,但问题页面links to a solution by Gabor Grothendieck建议在加载rJava包之前通过设置java.parameters选项来增加堆大小。(rJavaxlsx的依赖项。)

代码语言:javascript
复制
options(java.parameters = "-Xmx1000m")

1000是允许Java heap使用的内存的兆字节数;它可以替换为您喜欢的任何值。我的实验表明,值越大越好,并且您可以愉快地使用您的全部RAM权限。例如,我使用以下命令获得最好的结果:

代码语言:javascript
复制
options(java.parameters = "-Xmx8000m")

在具有8 8GB的机器上。

可以通过在循环的每次迭代中请求垃圾收集来获得进一步的改进。正如@gjabel所指出的,可以使用gc()执行R垃圾收集。我们可以定义一个调用Java System.gc()方法的Java垃圾收集函数:

代码语言:javascript
复制
jgc <- function()
{
  .jcall("java/lang/System", method = "gc")
}    

然后,可以将循环更新为:

代码语言:javascript
复制
for(i in seq_along(the_data))
{
  gc()
  jgc()
  message("Creating sheet", i)
  sheet <- createSheet(wb, sheetName = names(the_data)[i])
  message("Adding data frame", i)
  addDataFrame(the_data[[i]], sheet)
}

通过这两个代码修复,代码在抛出错误之前一直运行到i = 29

我尝试过的一种技术是在每次迭代时使用write.xlsx2将内容写入文件,但没有成功。这比其他代码慢,并且在第10次迭代时就崩溃了(但至少有部分内容被写入文件)。

代码语言:javascript
复制
for(i in seq_along(the_data))
{
  message("Writing sheet", i)
  write.xlsx2(
    the_data[[i]], 
    "test.xlsx", 
    sheetName = names(the_data)[i], 
    append    = i > 1
  )
}
票数 84
EN

Stack Overflow用户

发布于 2016-01-14 19:39:06

基于@richie-cotton的回答,我发现在jgc函数中添加gc()可以保持较低的CPU使用率。

代码语言:javascript
复制
jgc <- function()
{
  gc()
  .jcall("java/lang/System", method = "gc")
}    

我之前的for循环仍然在处理原始的jgc函数,但是有了额外的命令,我不再遇到GC overhead limit exceeded错误消息。

票数 8
EN

Stack Overflow用户

发布于 2017-10-11 19:23:35

上述错误的解决方案:请使用下面提到的r- code:

代码语言:javascript
复制
detach(package:xlsx)
detach(package:XLConnect)
library(openxlsx)

并且,尝试再次导入该文件,您将不会得到任何错误,因为它为我工作。

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

https://stackoverflow.com/questions/21937640

复制
相关文章

相似问题

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