2012-07-05 7 views
54

मेरे पास एक दिनचर्या है जो प्रति सेकंड कई बार SQLite डेटाबेस के विरुद्ध अलग-अलग क्वेरी चलाती है। थोड़ी देर के बाद मुझे त्रुटिएसक्यूलाइट एंड्रॉइड डाटाबेस कर्सर 2048 केबी की विंडो आवंटन

"android.database.CursorWindowAllocationException: - Cursor window allocation of 2048 kb failed. # Open Cursors = " लॉगकैट में दिखाई देगा।

मेरे पास ऐप लॉग मेमोरी उपयोग था, और वास्तव में जब उपयोग एक निश्चित सीमा तक पहुंच जाता है तो मुझे यह त्रुटि मिलती है, जिसका अर्थ है कि यह समाप्त हो जाता है। मेरा अंतर्ज्ञान मुझे बताता है कि जब भी मैं कोई प्रश्न चलाता हूं, तो डेटाबेस इंजन एक नया बफर (कर्सरविंडो) बना रहा है, और भले ही मैं .close() कर्सर को चिह्नित करता हूं, न तो कचरा कलेक्टर और न ही SQLiteDatabase.releaseMemory() स्मृति मुक्त करने में पर्याप्त तेज़ है। मुझे लगता है कि समाधान हमेशा एक ही बफर में लिखने के लिए डेटाबेस को "मजबूर" कर सकता है, और नए नहीं बना सकता है, लेकिन मैं ऐसा करने का कोई तरीका नहीं ढूंढ पाया। मैंने अपने स्वयं के कर्सर विन्डो को तुरंत चालू करने का प्रयास किया है, और इसे किसी भी लाभ के लिए और SQLiteCursor को सेट करने का प्रयास किया है।

¿कोई विचार?

संपादित करें: फिर से @GrahamBorland से उदाहरण कोड का अनुरोध:

public static CursorWindow cursorWindow = new CursorWindow("cursorWindow"); 
public static SQLiteCursor sqlCursor; 
public static void getItemsVisibleArea(GeoPoint mapCenter, int latSpan, int lonSpan) { 
query = "SELECT * FROM Items"; //would be more complex in real code 
sqlCursor = (SQLiteCursor)db.rawQuery(query, null); 
sqlCursor.setWindow(cursorWindow); 
} 

आदर्श रूप में मैं एक नई क्वेरी देने से पहले .setWindow() करने में सक्षम होना चाहते हैं, और डेटा मैं एक ही CursorWindow हर नए डेटा में डाल दिया है ।

+0

मैं नहीं पता है समस्या यह है क्या .. :) लेकिन मैं SQLiteOpenHelper वर्ग सिंगलटन बनाने के लिए इस्तेमाल करते हैं। तो मुझे इस तरह के किसी भी मुद्दे को कभी नहीं मिला। –

+0

नहीं, मैं SQLiteOpenHelper का उपयोग नहीं करता, मैं एक स्थिर डेटाएप क्लास बनाता हूं जिसमें SQLiteDatabase शामिल है। यह ठीक काम करता है और मुझे संदेह है कि समस्या वहां है। समस्या को एक ही कंटेनर को बार-बार उपयोग करने के बजाए, प्रत्येक नई क्वेरी के परिणाम रखने के लिए एक नया कंटेनर बनाने वाले SQLite लाइब्रेरीज़ के साथ और अधिक करना पड़ता है। और हालांकि मैं कर्सर को बंद कर सकता हूं, जिस दर पर जीसी साफ हो जाता है वह दर उस दर से धीमी है जिस पर नए कंटेनर बनाए जाते हैं, इस प्रकार मेमोरी होग का उत्पादन होता है। – alex

+0

क्या आप अपना कुछ कोड दिखा सकते हैं, विशेष रूप से आपने अपना स्वयं का 'कर्सरविंडो' सेट करने के साथ क्या करने की कोशिश की? –

उत्तर

88

अक्सर इस त्रुटि का कारण गैर बंद कर्सर नहीं हैं। सुनिश्चित करें कि आप उनका उपयोग करने के बाद सभी कर्सर बंद करें (यहां तक ​​कि किसी त्रुटि के मामले में)।

Cursor cursor = null; 
try { 
    cursor = db.query(... 
    // do some work with the cursor here. 
} finally { 
    // this gets called even if there is an exception somewhere above 
    if(cursor != null) 
     cursor.close(); 
} 
+0

आप वास्तव में बस उस उदाहरण को शून्य और शून्य जांच से बचने के लिए कर सकते हैं। – aij

+2

खुले फ़ाइल पॉइंटर्स की तरह - हमेशा यह सुनिश्चित करने के लिए कि आपका कोड साफ़ रूप से मौजूद है, अंत में अनुभाग को बंद करें। – slott

11

मैं सिर्फ इस मुद्दे का अनुभव किया है - और कर्सर को बंद नहीं की सुझाव दिया जवाब, जबकि वैध, नहीं मैं इसे कैसे तय हुई थी। मेरा मुद्दा डाटाबेस को बंद कर रहा था जब SQLite अपने कर्सर को दोबारा बदलने की कोशिश कर रहा था। मैं डाटाबेस खोलूंगा, डेटा सेट पर कर्सर प्राप्त करने के लिए डेटाबेस से पूछताछ करता हूं, डेटाबेस बंद कर देता हूं और कर्सर पर फिर से चलाता हूं। मैंने देखा कि जब भी मैं उस कर्सर में एक निश्चित रिकॉर्ड मारा, तो मेरा ऐप ओपी में इसी त्रुटि के साथ दुर्घटनाग्रस्त हो जाएगा।

मुझे लगता है कि कर्सर के लिए कुछ रिकॉर्ड्स तक पहुंचने के लिए, इसे डेटाबेस को फिर से पूछना होगा और यदि यह बंद है, तो यह इस त्रुटि को फेंक देगा। मैंने इसे बंद करने तक डेटाबेस को बंद नहीं किया जब तक कि मैंने आवश्यक सभी काम पूरा नहीं किया।

62

यदि आपको SQL कोड की एक महत्वपूर्ण राशि के माध्यम से खोदना है, तो आप StrictMode को सक्षम करने के लिए अपनी मुख्य गतिविधि में निम्न कोड स्निपेट डालकर अपने डिबगिंग को तेज़ी से बढ़ा सकते हैं। यदि लीक किए गए डेटाबेस ऑब्जेक्ट्स का पता लगाया गया है तो आपका ऐप अब लॉग जानकारी के साथ क्रैश हो जाएगा जहां आपका रिसाव ठीक है। इससे मुझे मिनटों के मामले में एक दुष्ट कर्सर का पता लगाने में मदद मिली।

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    if (BuildConfig.DEBUG) {  
     StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder() 
     .detectLeakedSqlLiteObjects() 
     .detectLeakedClosableObjects() 
     .penaltyLog() 
     .penaltyDeath() 
     .build()); 
    } 
    super.onCreate(savedInstanceState); 
    ... 
    ... 
+6

यह बढ़िया है! मैंने इस मानक को 'if (BuildConfig.DEBUG) {...} 'के साथ अपने मुख्य वर्ग के' स्थिर {...} 'ब्लॉक के अंदर बनाया है। –

+1

मुझे अब तक की इस तरह की समस्या को डीबग करने का सबसे अच्छा और सबसे प्रभावी तरीका स्वीकार्य उत्तर होना चाहिए! – androidseb

+0

ग्रेट! लेकिन रिलीज में StrictMode के बिना काम करेगा? – alfdev

0
public class CursorWindowFixer { 

    public static void fix() { 
    try { 
     Field field = CursorWindow.class.getDeclaredField("sCursorWindowSize"); 
     field.setAccessible(true); 
     field.set(null, 102400 * 1024); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
    } 
} 
+0

आपको अपने कोड – sme

+0

ब्रेकथ्रू कर्सर विन्डो सीमा केवल 2 मेगाबाइट की सीमा बताते हुए कुछ टिप्पणियां जोड़नी चाहिए –

संबंधित मुद्दे