Обработка java.ленг.OutOfMemoryError при записи в Excel из R
The xlsx
пакет может использоваться для чтения и записи электронных таблиц Excel из R. К сожалению, даже для умеренно больших электронных таблиц,java.lang.OutOfMemoryError
может произойти. В частности,
## Error in .jcall("RJavaTools", "Ljava/lang/Object;", "invokeMethod", cl, :
## java.lang.OutOfMemoryError: Java heap space
## Error in .jcall("RJavaTools", "Ljava/lang/Object;", "newInstance", .jfindClass(class), :
## java.lang.OutOfMemoryError: GC overhead limit exceeded
(другие связанные исключения также возможны, но реже.)
аналогичный вопрос был задан относительно этой ошибки при чтении электронных таблиц.
импорт большого xlsx файла в R?
основное преимущество использования электронных таблиц Excel в качестве данных носитель данных через CSV в том, что вы можете хранить несколько листов в одном файле, поэтому здесь мы рассмотрим список фреймов данных одного фрейма данных на листе. Этот пример набора данных содержит 40 фреймов данных, каждый с двумя столбцами до 200k строк. Он разработан, чтобы быть достаточно большим, чтобы быть проблематичным, но вы можете изменить размер, изменив n_sheets
и n_rows
.
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
, затем цикл по каждому кадру данных вызова createSheet
и addDataFrame
. Наконец, книга может быть записана в файл с помощью saveWorkbook
. Я добавил сообщения в цикл, чтобы было легче увидеть, где он падает.
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")
запуск этого в 64-бит на машине с 8 ГБ оперативной памяти, он бросает GC overhead limit exceeded
ошибка при запуске addDataFrame
в первый раз.
как писать большие наборы данных в Excel электронные таблицы с помощью xlsx
?
4 ответа:
это известная проблема: http://code.google.com/p/rexcel/issues/detail?id=33
пока не решена, страница проблема ссылки на решение by Габор Гротендика предполагая, что размер кучи должен быть увеличен путем установки до
rJava
пакет загружается. (rJava
зависимостьxlsx
.)options(java.parameters = "-Xmx1000m")
значение
1000
это количество мегабайт оперативной памяти, чтобы обеспечить Java кучи; он может заменить любое значение. Мои эксперименты с этим показывают, что большие значения лучше, и вы можете с радостью использовать свое полное право на ОЗУ. Например, я получил лучшие результаты, используя:options(java.parameters = "-Xmx8000m")
на машине с 8 ГБ оперативной памяти.
дальнейшее улучшение может быть получено путем запроса сборки мусора в каждой итерации цикла. Как отмечает @gjabel, сбор мусора R может быть выполнен с помощью
gc()
. Мы можем определите функцию сборки мусора Java, которая вызывает JavaSystem.gc()
способ:jgc <- function() { .jcall("java/lang/System", method = "gc") }
затем цикл может быть обновлен в:
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-й итерации (но, по крайней мере часть содержимого была записана в файл).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 ) }
основываясь на ответе @ richie-cotton, я нашел добавление
gc()
доjgc
функция поддерживала низкую загрузку ЦП.jgc <- function() { gc() .jcall("java/lang/System", method = "gc") }
мой петля все еще боролся с оригиналом
jgc
функция, но с дополнительной командой я больше не сталкиваюсь сGC overhead limit exceeded
сообщение об ошибке.