जब ब्राउज़र मेमोरी से बाहर निकलते हैं, तो वे इससे सबसे पुराने टैब को अनलोड करते हैं। यह कष्टप्रद है क्योंकि ऐसे टैब पर क्लिक करने से पृष्ठ पुनः लोड होता है। आज हम Habr पाठकों को बताएंगे कि Yandex.Browser टीम हाइबरनेट तकनीक का उपयोग करके इस समस्या को कैसे हल करती है।
क्रोमियम-आधारित ब्राउज़र प्रत्येक टैब के लिए एक प्रक्रिया बनाते हैं। इस दृष्टिकोण के कई फायदे हैं। यह सुरक्षा है (एक दूसरे से साइटों को अलग करना), स्थिरता (एक प्रक्रिया का क्रैश पूरे ब्राउज़र को नहीं खींचता है), और बड़ी संख्या में कोर के साथ आधुनिक प्रोसेसर पर काम का त्वरण। लेकिन एक माइनस भी है - सब कुछ के लिए एक प्रक्रिया का उपयोग करते समय की तुलना में एक उच्च मेमोरी खपत। यदि ब्राउज़र ने इसके साथ कुछ नहीं किया, तो उनके उपयोगकर्ता लगातार कुछ इस तरह देखेंगे:

क्रोमियम परियोजना में, वे विभिन्न कैश को साफ़ करके पृष्ठभूमि टैब की मेमोरी खपत से जूझ रहे हैं। यह उस कैश के बारे में नहीं है जिसमें लोड किए गए पृष्ठों की छवियां संग्रहीत की जाती हैं। उसके साथ कोई समस्या नहीं है - वह हार्ड ड्राइव पर रहता है। एक आधुनिक ब्राउज़र में, कई अन्य कैश्ड जानकारी हैं जो रैम में संग्रहीत हैं।
इसके अलावा, क्रोमियम पृष्ठभूमि टैब में जेएस टाइमर को रोकने के लिए काफी समय से काम कर रहा है। अन्यथा, कैश साफ़ करने का कोई मतलब नहीं है, क्योंकि पृष्ठभूमि टैब में गतिविधियाँ उन्हें पुनर्स्थापित करती हैं। यह माना जाता है कि यदि साइटें पृष्ठभूमि में काम करना चाहती हैं, तो आपको एक सेवा कार्यकर्ता का उपयोग करने की आवश्यकता है, न कि टाइमर।
यदि ये उपाय मदद नहीं करते हैं, तो स्मृति से संपूर्ण टैब रेंडरिंग प्रक्रिया को अनलोड करने के लिए केवल एक चीज बची है। एक खुली साइट बस अस्तित्व में है। यदि आप टैब पर जाते हैं, तो यह नेटवर्क से डाउनलोड होना शुरू हो जाता है। यदि टैब में एक विराम वीडियो था, तो यह शुरुआत से ही खेलना शुरू कर देगा। यदि पृष्ठ पर फ़ॉर्म भरा गया था, तो दर्ज की गई जानकारी खो सकती है। यदि एक भारी जेएस एप्लिकेशन ने टैब में काम किया है, तो आपको इसे फिर से शुरू करने की आवश्यकता होगी।
नेटवर्क तक पहुंच न होने पर अनलोडिंग टैब की समस्या विशेष रूप से अप्रिय है। क्या आपने हवाई जहाज पर पढ़ने के लिए हैबर के साथ एक टैब स्थगित कर दिया है? तैयार रहें कि एक उपयोगी लेख एक कद्दू में बदल जाएगा।
ब्राउज़र डेवलपर्स समझ रहे हैं कि यह चरम उपाय उपयोगकर्ताओं के लिए कष्टप्रद है (केवल अनुमान लगाने के
लिए खोज की ओर मुड़ें ), इसलिए वे इसे अंतिम क्षण में लागू करते हैं। इस बिंदु पर, कंप्यूटर पहले से ही मेमोरी की कमी के कारण धीमा हो रहा है, उपयोगकर्ता इस पर ध्यान देते हैं और समस्या को हल करने के लिए वैकल्पिक तरीकों की तलाश कर रहे हैं, इसलिए, उदाहरण के लिए,
द ग्रेट सस्पेंडर एक्सटेंशन में 1.4 मिलियन से अधिक उपयोगकर्ता हैं।
लोग चाहते हैं कि ब्राउज़र और मेमोरी को बचाया जाए, और वे धीमा नहीं करना शुरू करते हैं। ऐसा करने के लिए, अंतिम समय पर टैब को अनलोड नहीं किया जाना चाहिए, लेकिन थोड़ा पहले। और इसके लिए आपको टैब की सामग्री को खोने से रोकना होगा, अर्थात। बचत प्रक्रिया को अदृश्य बनाते हैं। लेकिन फिर क्या बचा? सर्कल बंद है। लेकिन एक समाधान मिल गया था।
Yandex ब्राउज़र में हाइबरनेट करें
हैबर के कई पाठक पहले से ही अनुमान लगा सकते हैं कि मेमोरी को क्या साफ करना है, लेकिन टैब की स्थिति को बचाने के लिए काफी संभव है यदि आप पहली बार हार्ड ड्राइव पर राज्य को अनलोड करते हैं। यदि आप हार्ड ड्राइव से टैब को पुनर्स्थापित करने के लिए एक टैब पर क्लिक करते हैं, तो उपयोगकर्ता कुछ भी नोटिस नहीं करेगा।
हमारी टीम क्रोमियम परियोजना के विकास में शामिल है, जहाँ यह महत्वपूर्ण
अनुकूलन संपादन और नई
सुविधाएँ भेजती
है । 2015 में वापस, हमने परियोजना के सहयोगियों के साथ हार्ड ड्राइव पर टैब की स्थिति बनाए रखने के विचार
पर चर्चा की और यहां तक कि कई सुधार करने में कामयाब रहे, लेकिन उन्होंने क्रोमियम में इस दिशा को स्थिर करने का फैसला किया। हमने Yandex.Browser में अलग और निरंतर विकास का निर्णय लिया। नियोजित की तुलना में अधिक समय लगा, लेकिन यह इसके लायक था। नीचे हम हाइबरनेट तकनीक के तकनीकी स्टफिंग के बारे में बात करेंगे, लेकिन अब, हम सामान्य तर्क के साथ शुरू करते हैं।
कई बार एक मिनट में, Yandex.Browser उपलब्ध स्मृति की मात्रा की जांच करता है, और यदि यह 600 मेगाबाइट के थ्रेशोल्ड मान से कम है, तो हाइबरनेट खेलने में आता है। यह सब इस तथ्य से शुरू होता है कि ब्राउज़र सबसे पुराना (उपयोग के लिए) पृष्ठभूमि टैब पाता है। वैसे, औसत उपयोगकर्ता के 7 टैब खुले हैं, लेकिन 5% में 30 से अधिक है।
आप किसी पुराने टैब को मेमोरी से अनलोड नहीं कर सकते - आप वास्तव में महत्वपूर्ण कुछ तोड़ सकते हैं। उदाहरण के लिए, संगीत खेलना या वेब मैसेंजर में चैट करना। अभी 28 ऐसे अपवाद हैं यदि टैब उनमें से कम से कम एक में फिट नहीं होता है, तो ब्राउज़र अगले एक की जांच करने के लिए आगे बढ़ता है।
यदि एक टैब पाया जाता है जो आवश्यकताओं को पूरा करता है, तो इसे बचाने की प्रक्रिया शुरू होती है।
हाइबरनेट में टैब को सहेजना और पुनर्स्थापित करना
किसी भी पेज को इंजन V8 (JS) और ब्लिंक (HTML / DOM) से जुड़े दो बड़े भागों में विभाजित किया जा सकता है। एक छोटे से उदाहरण पर विचार करें:
<html> <head> <script type="text/javascript"> function onLoad() { var div = document.createElement("div"); div.textContent = "Look ma, I can set div text"; document.body.appendChild(div); } </script> </head> <body onload="onLoad()"></body> </html>
हमारे पास कुछ DOM ट्रीप और एक छोटी सी स्क्रिप्ट है जो बस शरीर में एक div जोड़ती है। पलक के दृष्टिकोण से, यह पृष्ठ कुछ इस तरह दिखता है:

आइए HTMLBodyElement उदाहरण का उपयोग करते हुए Blink और V8 के बीच के संबंध को देखें:

आप देख सकते हैं कि ब्लिंक और वी 8 में समान संस्थाओं के अलग-अलग प्रतिनिधित्व हैं और एक-दूसरे से निकटता से संबंधित हैं। इसलिए हम मूल विचार पर आए - V8 की पूर्ण स्थिति को बचाने के लिए, और ब्लिंक के लिए पाठ के रूप में केवल HTML विशेषताओं को संग्रहीत करने के लिए। लेकिन यह एक गलती थी, क्योंकि हमने डोम ऑब्जेक्ट्स के उन राज्यों को खो दिया था जो विशेषताओं में संग्रहीत नहीं थे। हमने उन राज्यों को भी खो दिया है जो डोम में संग्रहीत नहीं थे। इस समस्या का हल ब्लिंक को पूरी तरह से बचाना था। लेकिन इतना सरल नहीं है।
पहले आपको ब्लिंक वस्तुओं के बारे में जानकारी एकत्र करने की आवश्यकता है। इसलिए, वी 8 को बचाने के समय, हम न केवल जेएस को रोकते हैं और इसे डालते हैं, बल्कि मेमोरी में जेएस के लिए उपलब्ध डोम ऑब्जेक्ट्स और अन्य सहायक वस्तुओं के संदर्भ भी एकत्र करते हैं। हम उन सभी वस्तुओं से भी गुज़रते हैं जिन्हें दस्तावेज़ की वस्तुओं तक पहुँचा जा सकता है - प्रत्येक पृष्ठ के मूल तत्व। इसलिए हम हर उस चीज के बारे में जानकारी एकत्र करते हैं जिसे संरक्षित करना महत्वपूर्ण है। सबसे मुश्किल हिस्सा बचाने के लिए सीख रहा है।
अगर हम सभी ब्लिंक वर्गों की गिनती करते हैं जो DOM ट्री का प्रतिनिधित्व करते हैं, साथ ही विभिन्न HTML5 API (उदाहरण के लिए, कैनवास, मीडिया, जियोलोकेशन), तो हमें हजारों कक्षाएं मिलती हैं। सभी वर्गों को अपने हाथों से बचाने के तर्क को लिखना लगभग असंभव है। लेकिन सबसे बुरी बात यह है कि अगर आप ऐसा करते हैं, तो भी इसे बनाए रखना असंभव होगा, क्योंकि हम नियमित रूप से क्रोमियम के नए संस्करणों को अपडेट करते हैं जो किसी भी वर्ग के लिए अप्रत्याशित परिवर्तन करते हैं।
सभी प्लेटफार्मों के लिए हमारा ब्राउज़र क्लैंग का उपयोग करके बनाया गया है। ब्लिंक कक्षाओं को संरक्षित करने की समस्या को हल करने के लिए, हमने क्लैंग के लिए एक प्लगइन बनाया, जो कक्षाओं के लिए एएसटी (सार सिंटैक्स ट्री) बनाता है। उदाहरण के लिए, यह कोड:
कक्षा कोड class Bar : public foo_namespace::Foo { struct BarInternal { int int_field_; float float_field_; } bar_internal_field_; std::string string_field_; };
यह ऐसे XML में बदल जाता है:
XML में प्लगइन का परिणाम <class> <name>bar_namespace::Bar::BarInternal</name> <is_union>false</is_union> <is_abstract>false</is_abstract> <decl_source_file>src/bar.h</decl_source_file> <base_class_names></base_class_names> <fields> <field> <name>int_field_</name> <type> <builtin> <is_const>0</is_const> <name>int</name> </builtin> </type> </field> <field> <name>float_field_</name> <type> <builtin> <is_const>0</is_const> <name>float</name> </builtin> </type> </field> </class> <class> <name>bar_namespace::Bar</name> <is_union>false</is_union> <is_abstract>false</is_abstract> <decl_source_file>src/bar.h</decl_source_file> <base_class_names> <class_name>foo_namespace::Foo</class_name> </base_class_names> <fields> <field> <name>bar_internal_field_</name> <type> <class> <is_const>0</is_const> <name>bar_namespace::Bar::BarInternal</name> </class> </type> </field> <field> <name>string_field_</name> <type> <class> <is_const>0</is_const> <name>std::string</name> </class> </type> </field> </fields> </class>
इसके अलावा, हमारे द्वारा लिखी गई अन्य स्क्रिप्ट इस जानकारी से C ++ कोड को सेविंग और रिस्टोर करने के लिए उत्पन्न करती हैं, जो Yandex.Brown सभा में आती है।
XML से स्क्रिप्ट द्वारा प्राप्त C ++ सेव कोड void serialize_bar_namespace_Bar_BarInternal( WriteVisitor* writer, Bar::BarInternal* instance) { writer->WriteBuiltin<size_t>(instance->int_vector_field_.size()); for (auto& item : instance->int_vector_field_) { writer->WriteBuiltin<int>(item); } writer->WriteBuiltin<float>(instance->float_field_); } void serialize_bar_namespace_Bar(WriteVisitor* writer, Bar* instance) { serialize_foo_namespace_Foo(writer, instance); serialize_bar_namespace_Bar_BarInternal( writer, &instance->bar_internal_field_); writer->WriteString(instance->string_field_); }
कुल मिलाकर, हम लगभग 1000 ब्लिंक वर्गों के लिए कोड तैयार करते हैं। उदाहरण के लिए, हमने ऐसे जटिल वर्ग को कैनवस के रूप में सहेजना सीखा। आप इसे जेएस कोड में आकर्षित कर सकते हैं, कई गुण सेट कर सकते हैं, ड्राइंग के लिए ब्रश पैरामीटर सेट कर सकते हैं, और इसी तरह। हम इन सभी गुणों, मापदंडों और चित्र को स्वयं सहेजते हैं।
हार्ड डिस्क के सभी डेटा को सफलतापूर्वक एन्क्रिप्ट करने और सहेजने के बाद, उपयोगकर्ता द्वारा इस टैब पर लौटने तक टैब प्रक्रिया को मेमोरी से अनलोड किया जाता है। इंटरफ़ेस में, पहले की तरह, यह बाहर खड़ा नहीं है।
टैब पुनर्प्राप्ति तात्कालिक नहीं है, लेकिन नेटवर्क से डाउनलोड करने की तुलना में काफी तेज है। फिर भी, हम एक मुश्किल चाल में चले गए ताकि उपयोगकर्ताओं को एक सफेद स्क्रीन की चमक के साथ परेशान न करें। हम सेव फेज के दौरान बनाए गए पेज का स्क्रीनशॉट दिखाते हैं। यह संक्रमण को सुचारू बनाने में मदद करता है। अन्यथा, पुनर्प्राप्ति प्रक्रिया सामान्य नेविगेशन के समान एकमात्र अंतर के साथ है जो ब्राउज़र नेटवर्क अनुरोध नहीं करता है। यह फ्रेम संरचना और डोम पेड़ों को फिर से बनाता है, और फिर वी 8 की स्थिति को बदल देता है।
हमने स्पष्ट वीडियो के साथ एक वीडियो रिकॉर्ड किया कि टेक्स्ट और वीडियो स्थिति में दर्ज किए गए JS गेम में प्रगति को संरक्षित करते हुए हाइबरनेट को कैसे अनलोड और पुनर्स्थापना पर क्लिक-थ्रू पुनर्स्थापित करता है:
परिणाम
निकट भविष्य में, विंडोज के लिए Yandex.Browser के सभी उपयोगकर्ताओं के लिए हाइबरनेट तकनीक उपलब्ध हो जाएगी। हमने एंड्रॉइड के लिए अल्फा संस्करण में इसके साथ प्रयोग करना शुरू करने की भी योजना बनाई है। इसके साथ, ब्राउज़र मेमोरी को पहले की तुलना में अधिक कुशलता से बचाता है। उदाहरण के लिए, बड़ी संख्या में खुले टैब वाले उपयोगकर्ताओं के लिए, हाइबरनेट औसतन 330 मेगाबाइट मेमोरी से अधिक बचाता है और टैब में जानकारी नहीं खोता है, जो किसी भी नेटवर्क स्थिति में एक क्लिक में सुलभ रहता है। हम समझते हैं कि यह अनछुए पृष्ठभूमि टैब पर विचार करने के लिए वेबमास्टरों के लिए उपयोगी होगा, इसलिए हम
पेज लाइफसाइकल एपीआई का समर्थन करने की योजना बनाते हैं।
संसाधनों को बचाने के उद्देश्य से हाइबरनेट हमारा एकमात्र समाधान नहीं है। यह पहला वर्ष नहीं है जब हम यह सुनिश्चित करने के लिए काम कर रहे हैं कि ब्राउज़र सिस्टम में उपलब्ध संसाधनों के लिए अनुकूल है। उदाहरण के लिए, कमजोर उपकरणों पर, ब्राउज़र सरलीकृत मोड में प्रवेश करता है, और जब लैपटॉप को पावर स्रोत से डिस्कनेक्ट किया जाता है, तो यह बिजली की खपत करता है। संसाधनों को सहेजना एक बड़ी और जटिल कहानी है, जिसके बारे में हम निश्चित रूप से हैबे में लौटेंगे।