javascript - QML कचरा संग्रह उपयोग में आने वाली वस्तुओं को हटा देता है




qt garbage-collection (2)

मैंने कई बार इस समस्या का सामना किया है, चाहे वे क्यूएमएल या सी ++ में बनाई गई हों, गतिशील रूप से बनाई गई वस्तुओं के साथ। वस्तुओं का उपयोग करते समय हटा दिया जाता है, जिससे बिना किसी स्पष्ट कारण के हार्ड क्रैश हो जाता है। ऑब्जेक्ट्स को अभी भी संदर्भित किया जाता है और अन्य ऑब्जेक्ट्स को रूट ऑब्जेक्ट के लिए नीचे की ओर देखा जाता है, इसलिए मुझे QML के लिए उन ऑब्जेक्ट्स को हटाना अजीब लगता है, जबकि उनकी रीफोकाउंट अभी भी शून्य से ऊपर है।

अब तक मैंने जो एकमात्र समाधान पाया, वह था कि वस्तुओं को C ++ में बनाना और स्वामित्व को CPP में स्पष्ट रूप से सेट करना, जिससे QML से वस्तुओं को हटाना असंभव हो गया।

सबसे पहले मैंने यह माना कि यह पेरेंटिंग के साथ एक समस्या हो सकती है, क्योंकि मैं QObject व्युत्पन्न वर्गों का उपयोग कर रहा था, और QML विधि डायनामिक इंस्ट्रूमेंटेशन एक अभिभावक के लिए एक Item पास करता है, जबकि QtObject एक मूल संपत्ति के साथ नहीं आता है - यह उजागर नहीं है QObject

लेकिन फिर मैंने एक Qobject व्युत्पन्न के साथ प्रयास किया, जो पेरेंटिंग को उजागर करता है और उपयोग करता है और अंत में Item का उपयोग करने की कोशिश भी करता है ताकि यह सुनिश्चित हो सके कि ऑब्जेक्ट ठीक से पेरेंट हैं, और फिर भी यह व्यवहार अभी भी कायम है।

यहाँ एक उदाहरण है जो इस व्यवहार को उत्पन्न करता है, दुर्भाग्य से मैं इसे एक स्रोत तक नहीं समतल कर सका क्योंकि Component के गहरे नेस्टिंग इसे तोड़ते हैं:

// ObjMain.qml
Item {
    property ListModel list : ListModel { }
    Component.onCompleted: console.log("created " + this + " with parent " + parent)
    Component.onDestruction: console.log("deleted " + this)
}

// Uimain.qml
Item {
    id: main
    width: childrenRect.width
    height: childrenRect.height
    property Item object
    property bool expanded : true
    Loader {
        id: li
        x: 50
        y: 50
        active: expanded && object && object.list.count
        width: childrenRect.width
        height: childrenRect.height
        sourceComponent: listView
    }
    Component {
        id: listView
        ListView {
            width: contentItem.childrenRect.width
            height: contentItem.childrenRect.height
            model: object.list
            delegate: Item {
                id: p
                width: childrenRect.width
                height: childrenRect.height
                Component.onCompleted: Qt.createComponent("Uimain.qml").createObject(p, {"object" : o})
            }
        }
    }
    Rectangle {
        width: 50
        height: 50
        color: "red"

        MouseArea {
            anchors.fill: parent
            acceptedButtons: Qt.RightButton | Qt.LeftButton
            onClicked: {
                if (mouse.button == Qt.RightButton) {
                    expanded = !expanded
                } else {
                    object.list.append({ "o" : Qt.createComponent("ObjMain.qml").createObject(object) })
                }
            }
        }
    }
}

// main.qml

Window {
    visible: true
    width: 1280
    height: 720

    ObjMain {
        id: obj
    }

    Uimain {
        object: obj
    }
}

उदाहरण एक तुच्छ वस्तु वृक्ष बिल्डर है, जिसमें बाएं बटन को नोड में एक पत्ता जोड़कर और दायां बटन नोड को ढहता है। बग को पुन: उत्पन्न करने के लिए सभी को 3 की गहराई के साथ एक नोड बनाना है और फिर रूट नोड का विस्तार और विस्तार करना है, जिस पर कंसोल आउटपुट की मात्रा है:

qml: created ObjMain_QMLTYPE_0(0x1e15bb8) with parent QQuickRootItem(0x1e15ca8)
qml: created ObjMain_QMLTYPE_0(0x1e5afc8) with parent ObjMain_QMLTYPE_0(0x1e15bb8)
qml: created ObjMain_QMLTYPE_0(0x1e30f58) with parent ObjMain_QMLTYPE_0(0x1e5afc8)
qml: deleted ObjMain_QMLTYPE_0(0x1e30f58)

डीप नोड नोड का object बिना किसी कारण के हटा दिया जाता है, भले ही यह मूल नोड Item के लिए प्रतिमानित हो और सूची मॉडल में JS ऑब्जेक्ट में संदर्भित हो। गहरे नोड में एक नया नोड जोड़ने का प्रयास करने से प्रोग्राम क्रैश हो जाता है।

व्यवहार सुसंगत है, चाहे पेड़ की संरचना की परवाह किए बिना, नोड्स का केवल दूसरा स्तर बचता है, पेड़ के ढह जाने पर सभी गहरे नोड खो जाते हैं।

गलती स्टोरेज के रूप में उपयोग किए जा रहे सूची मॉडल में नहीं है, मैंने एक जेएस सरणी और एक QList साथ परीक्षण किया है और ऑब्जेक्ट अभी भी खो गए हैं। यह उदाहरण केवल C ++ मॉडल के अतिरिक्त कार्यान्वयन को बचाने के लिए एक सूची मॉडल का उपयोग करता है। एकमात्र उपाय जो मैंने अब तक पाया, वह था कि वस्तुओं के QML स्वामित्व को पूरी तरह से अस्वीकार करना। हालांकि यह उदाहरण उत्पादन में लगातार व्यवहार करता है, लेकिन उत्पादन कोड में सहज विलोपन अक्सर पूरी तरह से मनमाना होता है।

कचरा संग्रहकर्ता के संबंध में - मैंने इसे पहले परीक्षण किया है, और यह देखा है कि यह काफी उदार है - वस्तुओं को बनाना और हटाना 100 एमबी रैम वर्म ने उस मेमोरी को जारी करने के लिए कचरा संग्रह को ट्रिगर नहीं किया, और फिर भी इस मामले में कुछ ही वस्तुओं, कुछ सौ बाइट्स के मूल्य जल्दबाजी में हटाए जा रहे हैं।

प्रलेखन के अनुसार, जिन वस्तुओं में माता-पिता या जेएस द्वारा संदर्भित होते हैं, उन्हें हटाया नहीं जाना चाहिए, और मेरे मामले में, दोनों वैध हैं:

ऑब्जेक्ट जावास्क्रिप्ट के स्वामित्व में है। जब किसी विधि कॉल के वापसी मूल्य के रूप में QML को ऑब्जेक्ट वापस किया जाता है, तो QML इसे ट्रैक करेगा और हटा देगा यदि कोई जावास्क्रिप्ट जावास्क्रिप्ट इसके शेष नहीं हैं और इसका कोई QObject नहीं है :: माता-पिता ()

जैसा कि फिलिप के उत्तर में उल्लेख किया गया है, ऐसा तब नहीं होता है जब ऑब्जेक्ट किसी फ़ंक्शन द्वारा बनाए जाते हैं जो कि नष्ट हो जाने वाली वस्तु में नहीं होता है, इसलिए इसका QML वस्तुओं से जुड़े अस्पष्ट रूप से उल्लिखित JS राज्य के साथ कुछ करना हो सकता है, लेकिन मैं अनिवार्य रूप से हूं अभी भी अंधेरे में क्यों विलोपन होता है, इसलिए प्रश्न प्रभावी रूप से अनुत्तरित है।

किसी भी विचार यह क्या कारण है?

अद्यतन: नौ महीने बाद भी इस महत्वपूर्ण बग पर शून्य विकास। इस बीच मैंने कई अतिरिक्त परिदृश्यों की खोज की जहां वस्तुएं अभी भी उपयोग में हैं, ऐसे परिदृश्य हटाए गए हैं, जिनमें यह कोई फर्क नहीं पड़ता है कि वस्तु कहां बनाई गई थी और मुख्य qml फ़ाइल में केवल ऑब्जेक्ट बनाने के लिए वर्कअराउंड लागू नहीं होता है। सबसे अजीब बात यह है कि वस्तुओं को तब नष्ट नहीं किया जा रहा है जब उन्हें "अन-रेफ़रेंस" किया जा रहा है, लेकिन जैसा कि उन्हें "पुनः संदर्भित" किया जा रहा है। यही है, वे नष्ट नहीं किए जा रहे हैं जब दृश्य वस्तुओं को संदर्भित करता है कि वे नष्ट हो रहे हैं, लेकिन जब उन्हें फिर से बनाया जा रहा है।

अच्छी खबर यह है कि क्यूएमएल में बनाई गई वस्तुओं के लिए भी सी ++ के लिए स्वामित्व सेट करना अभी भी संभव है, इसलिए क्यूएमएल में ऑब्जेक्ट निर्माण का लचीलापन नहीं खोता है। प्रत्येक वस्तु को सुरक्षित रखने और हटाने के लिए एक फ़ंक्शन को कॉल करने के लिए मामूली असुविधा है, लेकिन कम से कम आप QtQuick के छोटी गाड़ी के आजीवन प्रबंधन से बचते हैं। हालांकि, QML की "सुविधा" से प्यार है - मैनुअल ऑब्जेक्ट लाइफटाइम प्रबंधन के लिए मजबूर किया जा रहा है।


.Js फ़ाइल के अंदर एक सरणी बनाएं और फिर var myArray = []; साथ उस सरणी का एक उदाहरण बनाएं var myArray = []; उस .js. के शीर्ष-स्तर पर .js. फ़ाइल।

अब आप किसी भी ऑब्जेक्ट को संदर्भित कर सकते हैं जिसे आप myArray शामिल करते हैं, जो गतिशील रूप से बनाए गए हैं।

जब तक वे परिभाषित रहते हैं, तब तक कचरा संग्रह द्वारा जावास्क्रिप्ट संस्करण हटाए नहीं जाते हैं, इसलिए यदि आप एक वैश्विक वस्तु के रूप में परिभाषित करते हैं, तो अपने qml दस्तावेज़ में उस जावास्क्रिप्ट फ़ाइल को शामिल करें, यह तब तक रहेगा जब तक मुख्य QML दायरे में है।

नामक फ़ाइल में: backend.js

var tiles = [];

function create_square(new_square) {
    var component = Qt.createComponent("qrc:///src_qml/src_game/Square.qml");
    var sq = component.createObject(background, { "backend" : new_square });
    sq.x = new_square.tile.x
    sq.y = new_square.tile.y
    sq.width = new_square.tile.width;
    sq.height = new_square.tile.height;
    tiles[game.board.getIndex(new_square.tile.row, new_square.tile.col)] = sq;
    sq.visible = true;
}

संपादित करें :

मुझे थोड़ा और स्पष्ट रूप से समझाएं कि यह आपके विशेष वृक्ष उदाहरण पर कैसे लागू हो सकता है।

लाइन property Item object का उपयोग करके आप अनजाने में इसे आइटम की संपत्ति होने के लिए मजबूर कर रहे हैं, जिसे क्यूएमएल में अलग तरीके से व्यवहार किया जाता है। विशेष रूप से, गुण कचरा संग्रह के संदर्भ में नियमों के एक अनूठे सेट के तहत आते हैं, क्योंकि क्यूएमएल इंजन बस चलाने के लिए आवश्यक मेमोरी को कम करने के लिए किसी भी वस्तु के गुणों को निकालना शुरू कर सकता है।

इसके बजाय, अपने QML दस्तावेज़ के शीर्ष पर, इस पंक्ति को शामिल करें:

import "./object_file.js" as object_file

फिर फ़ाइल object_file.js में , इस पंक्ति को शामिल करें:

 var object_hash = []; 

अब आप अपने गतिशील रूप से बनाए गए घटकों को बचाने के लिए किसी भी समय object_hash उपयोग कर सकते हैं और उन्हें संदर्भित करके नष्ट होने से रोक सकते हैं

object_file.object_hash

वस्तु।

पागल बदलते स्वामित्व आदि को जाने की आवश्यकता नहीं है


मेमोरी को मैनेज करने के तरीके में QML C ++ नहीं है। क्यूएमएल का उद्देश्य स्मृति को आवंटित करने और इसे जारी करने के बारे में ध्यान रखना है। मुझे लगता है कि आपको जो समस्या मिली है वह सिर्फ इसी का परिणाम है।

यदि डायनेमिक ऑब्जेक्ट क्रिएशन बहुत गहरा हो जाता है, तो सब कुछ डिलीट होता दिख रहा है। इसलिए इससे कोई फर्क नहीं पड़ता कि आपकी बनाई गई वस्तुएं डेटा का एक हिस्सा थीं - वे भी नष्ट हो जाती हैं।

दुर्भाग्य से मेरा ज्ञान यहीं समाप्त होता है।

समस्या के इर्द-गिर्द काम करते हुए (मेरे पिछले कथन को साबित करते हुए) गतिशील UI qml फ़ाइलों से डेटा संरचना के निर्माण को आगे बढ़ा रहा है:

  1. उदाहरण के लिए main.qml में प्लेस ऑब्जेक्ट बनाएं

function createNewObject(parentObject) {
    parentObject.list.append({ "o" : Qt.createComponent("ObjMain.qml").createObject(parentObject) })
}
  1. अपने कोड में इस फ़ंक्शन का उपयोग करें:

// fragment of the Uimain.qml file
    MouseArea {
        anchors.fill: parent
        acceptedButtons: Qt.RightButton | Qt.LeftButton
        onClicked: {
            if (mouse.button == Qt.RightButton) {
                expanded = !expanded
            } else {
                createNewObject(object)
            }
        }
    }




qtquick2