हैंडलिंग जब java.lang.OutOfMemoryError R से एक्सेल को लिखते समय


84

xlsxपैकेज पढ़ सकते हैं और दुर्भाग्य से आर से एक्सेल स्प्रेडशीट बारे में, यहां तक कि मामूली बड़े स्प्रेडशीट के लिए करने के लिए इस्तेमाल किया जा सकता java.lang.OutOfMemoryErrorहो सकता है। विशेष रूप से,

त्रुटि injcall ("RJavaTools", "Ljava / lang / वस्तु?", "InvokeMethod", cl:
java.lang.OutOfMemoryError: Java हीप स्पेस

त्रुटि .jcall ("RJavaTools", "Ljava / lang / Object?", "NewInstance", .jfindClass (वर्ग):
java.lang.OutOfMemoryError: GC ओवरहेड सीमा से अधिक हो गई है।

(अन्य संबंधित अपवाद भी संभव हैं लेकिन दुर्लभ हैं।)

स्प्रेडशीट पढ़ते समय इस त्रुटि के बारे में एक समान प्रश्न पूछा गया था।

आर में एक बड़ा xlsx फ़ाइल आयात करना?

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")  

8GB रैम वाली मशीन पर 64-बिट में इसे GC overhead limit exceededचलाने पर addDataFrame, यह पहली बार रन करते समय त्रुटि को फेंक देता है ।

मैं एक्सेल स्प्रेडशीट का उपयोग करके बड़े डेटासेट कैसे लिख सकता हूं xlsx?

जवाबों:


79

यह एक ज्ञात समस्या है: http://code.google.com/p/rexcel/issues/detail?id=33

अनसुलझे होते समय, समस्या पृष्ठ गैबोर ग्रोथेंडिक द्वारा एक समाधान के लिए लिंक देता है , जिसमें सुझाव दिया जाता है कि पैकेज लोड होने से पहले विकल्प सेट करके ढेर का आकार बढ़ाया जाना चाहिए । ( की निर्भरता है ।)java.parametersrJavarJavaxlsx

options(java.parameters = "-Xmx1000m")

मान 1000जावा ढेर के लिए अनुमति देने के लिए मेगाबाइट रैम की संख्या है; इसे आपकी पसंद के किसी भी मूल्य के साथ बदला जा सकता है। इसके साथ मेरे प्रयोगों से पता चलता है कि बड़े मूल्य बेहतर हैं, और आप खुशी से अपने पूर्ण रैम एंटाइटेलमेंट का उपयोग कर सकते हैं। उदाहरण के लिए, मुझे सबसे अच्छे परिणाम मिले हैं:

options(java.parameters = "-Xmx8000m")

8GB रैम के साथ मशीन पर।

लूप के प्रत्येक पुनरावृत्ति में एक कचरा संग्रह का अनुरोध करके एक और सुधार प्राप्त किया जा सकता है। जैसा कि @gjabel द्वारा उल्लेख किया गया है, आर कचरा संग्रह का उपयोग करके किया जा सकता है gc()। हम जावा कचरा संग्रह फ़ंक्शन को परिभाषित कर सकते हैं जो जावा System.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
  )
}

38
इस पूरी समस्या को अब xlsxपैकेज के लिए स्वैप करने से दूर किया जा सकता है openxlsx, जो Rcppजावा के बजाय निर्भर है ।
रिची कॉटन

4
readxlएक और नया C / C ++ विकल्प है जो आशाजनक लगता है।
रिची कॉटन

1
दुर्भाग्य से मैंने पाया है कि वे दोनों डेट्स का पता लगाने और पढ़ने के लिए काफी कबाड़ हैं - दोनों ही उस एक्जिस्टिबल मेस में हैं जो एक्सेल डेट फॉर्मेट है: \
माइकलचिरिको

2
@ रिचीकॉनटन, अच्छा विकल्प। हालाँकि, ओपनएक्सएलएक्सएक्स .xls या .xlm फ़ाइलों को नहीं पढ़ सकता है! (2007 एक्सेल फाइल फॉर्मेट)।
एस्पांटा

फोन options(java.parameters = "-Xmx8000m")लोड से पहले rJava, xlsxjars, xlsxहल Error in .jcall("RJavaTools", "Ljava/lang/Object;", "invokeMethod", cl, : org.apache.poi.POIXMLException: java.lang.reflect.InvocationTargetException Calls: getNetwork ... <Anonymous> -> .jrcall -> .jcall -> .jcheck -> .Call Execution haltedRHEL 6.3 x86_64 में, जावा 1.7.0_79 (Oracle), rJava_0.9-7, xlsxjars_0.6.0, xlsx_0.5.7
निक दांग

7

@ रिची-कपास जवाब पर बिल्डिंग, मैंने पाया जोड़ने gc()के लिए jgcसमारोह CPU उपयोग कम रखा।

jgc <- function()
{
  gc()
  .jcall("java/lang/System", method = "gc")
}    

मेरा पिछला forलूप अभी भी मूल jgcफ़ंक्शन से जूझ रहा है , लेकिन अतिरिक्त कमांड के साथ, मैं अब GC overhead limit exceededत्रुटि संदेश में नहीं चलता ।


-1

यदि आप पंक्ति द्वारा पंक्ति लिख रहे हैं, तो आप लूप के अंदर gc () का भी उपयोग कर सकते हैं। जीसी () कचरा संग्रहण के लिए खड़ा है। जीसी () का उपयोग मेमोरी इश्यू के किसी भी मामले में किया जा सकता है।


-1

उपरोक्त त्रुटि का समाधान: कृपया नीचे दिए गए r - कोड का उपयोग करें:

detach(package:xlsx)
detach(package:XLConnect)
library(openxlsx)

और, फ़ाइल को फिर से आयात करने का प्रयास करें और आपको कोई त्रुटि नहीं मिलेगी क्योंकि यह मेरे लिए काम करता है।


दो टिप्पणियाँ: xlConnect में एक ही समस्या है। और इससे भी महत्वपूर्ण बात यह है कि किसी को एक अलग पुस्तकालय का उपयोग करने के बारे में बताने से समस्या का समाधान नहीं होता है। यहाँ लक्ष्य xlsx पैकेज में रहना है। XLConnect को समर्पित अन्य धागे हैं।
माइकल Tuchman

-1

मुझे पढ़ने के बजाय लिखने के साथ मुद्दे थे। xlsx () पढ़ने के बजाय .... लेकिन तब मुझे एहसास हुआ कि मैं गलती से 32 बिट आर चला रहा था। इसे 64 बिट पर स्वैप करने से यह मुद्दा तय हो गया।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.