Computer >> कंप्यूटर ट्यूटोरियल >  >> प्रोग्रामिंग >> Ruby

रूबी इंटर्नल्स उजागर: ऑब्जेक्ट मेमोरी लेआउट को समझना

क्या आप रूबी इंटर्नल्स का एक त्वरित दौरा चाहेंगे?

तो आप एक ट्रीट के लिए तैयार हैं।

क्योंकि...

हम एक साथ पता लगाने जा रहे हैं कि एक रूबी ऑब्जेक्ट मेमोरी में कैसे लेआउट होता है और आप कुछ अच्छी चीजें करने के लिए आंतरिक डेटा संरचनाओं में हेरफेर कैसे कर सकते हैं।

सीट बेल्ट बांधें और रूबी इंटरप्रेटर की गहराई में यात्रा के लिए तैयार हो जाएं!

सरणियों का मेमोरी लेआउट

जब आप एक सरणी बनाते हैं, तो रूबी को उसका बैकअप लेने के लिए कुछ सिस्टम मेमोरी और थोड़े मेटाडेटा की आवश्यकता होती है।

मेटाडेटा में शामिल हैं:

  • सरणी आकार (आइटम काउंट)
  • सरणी क्षमता
  • क्लास
  • ऑब्जेक्ट स्थिति (फ्रीज्ड या नहीं)
  • पॉइंटर जहां डेटा मेमोरी में संग्रहीत है

चूंकि मुख्य रूबी इंटरप्रेटर (MRI) C में लिखा गया है इसलिए कोई ऑब्जेक्ट्स नहीं हैं।

लेकिन कुछ और है: स्ट्रक्ट्स।

C में एक स्ट्रक्ट आपको संबंधित डेटा को एक साथ संग्रहीत करने में मदद करता है, और इसका उपयोग MRI के स्रोत कोड में Array, String और अन्य प्रकार के ऑब्जेक्ट्स को प्रस्तुत करने के लिए बहुत किया जाता है।

उन स्ट्रक्ट्स में से एक को देखकर हम एक ऑब्जेक्ट के मेमोरी लेआउट का अनुमान लगा सकते हैं।

तो आइए Array के लिए स्ट्रक्ट को देखें, जिसे RArray कहा जाता है:

 struct RArray { struct RBasic basic; union { struct { long len; union { long capa; VALUE shared; } aux; const VALUE *ptr; } heap; const VALUE ary[RARRAY_EMBED_LEN_MAX]; } as; }; 

मुझे पता है कि यह थोड़ा डराने वाला लग सकता है अगर आप C से परिचित नहीं हैं, लेकिन चिंता न करें! मैं इसे आसानी से पचने योग्य टुकड़ों में तोड़ने में आपकी मदद करूंगा 🙂

पहली चीज जो हमारे पास है वह है यह RBasic चीज़, जो भी एक स्ट्रक्ट है:

 struct RBasic { VALUE flags; VALUE klass; } 

यह कुछ ऐसा है जो अधिकांश रूबी ऑब्जेक्ट्स में होता है और इसमें कुछ चीजें होती हैं जैसे इस ऑब्जेक्ट के लिए क्लास और कुछ बाइनरी फ्लैग्स जो कहते हैं कि यह ऑब्जेक्ट फ्रीज्ड है या नहीं (और 'टेंटेड' विशेषता जैसी अन्य चीजें)।

दूसरे शब्दों में:

RBasic ऑब्जेक्ट के लिए जेनेरिक मेटाडेटा रखता है।

उसके बाद हमारे पास एक और स्ट्रक्ट है, जिसमें सरणी की लंबाई (len) होती है।

यूनियन एक्सप्रेशन कह रहा है कि aux या तो capa (क्षमता के लिए) या shared हो सकता है। यह ज्यादातर एक ऑप्टिमाइज़ेशन चीज़ है, जिसे पैट शॉघनेसी के इस उत्कृष्ट पोस्ट में अधिक विस्तार से समझाया गया है। मेमोरी आवंटन के संदर्भ में, कंपाइलर यूनियन के अंदर सबसे बड़े प्रकार का उपयोग करेगा।

फिर हमारे पास ptr है, जिसमें वह मेमोरी एड्रेस होता है जहां वास्तविक Array डेटा संग्रहीत होता है।

यहां एक तस्वीर है कि यह कैसा दिखता है (हर सफेद/ग्रे बॉक्स 32-बिट सिस्टम में 4 बाइट्स है):

रूबी इंटर्नल्स उजागर: ऑब्जेक्ट मेमोरी लेआउट को समझना

आप ObjectSpace मॉड्यूल का उपयोग करके किसी ऑब्जेक्ट का मेमोरी आकार देख सकते हैं:

 require 'objspace' ObjectSpace.memsize_of([]) # 20 

अब हम कुछ मस्ती करने के लिए तैयार हैं!

Fiddle: एक मजेदार प्रयोग

RBasic 32-बिट सिस्टम में ठीक 8 बाइट्स और 64-बिट सिस्टम में 16 बाइट्स है। यह जानकर हम Fiddle मॉड्यूल का उपयोग करके किसी ऑब्जेक्ट के लिए रॉ मेमोरी बाइट्स तक पहुंच सकते हैं और कुछ मजेदार प्रयोगों के लिए उन्हें बदल सकते हैं।

उदाहरण के लिए:

हम एक सिंगल बिट को टॉगल करके फ्रीज्ड स्थिति को बदल सकते हैं।

यह सार रूप में वही है जो फ्रीज़ मेथड करता है, लेकिन ध्यान दें कि कोई अनफ्रीज़ मेथड नहीं है।

आइए इसे सिर्फ मनोरंजन के लिए लागू करें!

सबसे पहले, Fiddle मॉड्यूल (रूबी स्टैंडर्ड लाइब्रेरी का हिस्सा) को require करें और एक फ्रीज्ड स्ट्रिंग बनाएं।

 require 'fiddle' str = 'water'.freeze str.frozen? # true 

अगला:

हमें अपनी स्ट्रिंग के लिए मेमोरी एड्रेस चाहिए, जिसे इस तरह प्राप्त किया जा सकता है।

 memory_address = str.object_id * 2 

अंत में:

हम उस सटीक बिट को फ्लिप करते हैं जिसे रूबी यह देखने के लिए जांचता है कि कोई ऑब्जेक्ट फ्रीज्ड है या नहीं। हम frozen? मेथड को कॉल करके भी जांचते हैं कि यह काम किया या नहीं।

 Fiddle::Pointer.new(memory_address)[1] ^= 8 str.frozen? # false 

ध्यान दें कि इंडेक्स [1] flags मान के दूसरे बाइट को संदर्भित करता है (जो कुल 4 बाइट्स से बना है)।

फिर हम ^= का उपयोग करते हैं जो "XOR" (एक्सक्लूसिव OR) ऑपरेटर है उस बिट को फ्लिप करने के लिए।

हम ऐसा इसलिए करते हैं क्योंकि flags के अंदर अलग-अलग बिट्स के अलग-अलग अर्थ होते हैं और हम कुछ असंबंधित बदलना नहीं चाहते।

अगर आपने मेरा रूबी ट्रिक्स पोस्ट पढ़ा है तो आपने इसे पहले देखा होगा, लेकिन अब आप जानते हैं कि यह कैसे काम करता है 🙂

एक और चीज़ जो आप आजमा सकते हैं वह है सरणी की लंबाई बदलना और सरणी प्रिंट करना।

आप देखेंगे कि सरणी छोटी हो जाती है!

आप यहां तक कि क्लास को बदलकर एक Array को यह सोचने पर मजबूर कर सकते हैं कि यह एक String है...

निष्कर्ष

आपने रूबी के हुड के नीचे कैसे काम करता है इसके बारे में थोड़ा सीखा। रूबी ऑब्जेक्ट्स के लिए मेमोरी कैसे लेआउट होती है और आप उस के साथ खेलने के लिए Fiddle मॉड्यूल का उपयोग कैसे कर सकते हैं।

आपको शायद असली ऐप में इस तरह Fiddle का उपयोग नहीं करना चाहिए, लेकिन इसके साथ प्रयोग करना मजेदार है।

इस पोस्ट को शेयर करना न भूलें ताकि अधिक लोग इसे देख सकें 🙂

  1. Stoffle प्रोग्रामिंग भाषा के लिए Ruby-आधारित पार्सर बनाना Stoffle प्रोग्रामिंग भाषा के लिए Ruby-आधारित पार्सर बनाना

    GitHub पर पूर्ण स्रोत Stoffle प्रोग्रामिंग भाषा का एक पूर्ण कार्यान्वयन GitHub पर उपलब्ध है। इस रेफरेंस कार्यान्वयन में कोड पढ़ने को आसान बनाने के लिए बहुत सारे कमेंट्स हैं। यदि आपको बग मिलते हैं या आपके कोई प्रश्न हैं तो बेझिझक एक इश्यू खोलें। इस ब्लॉग पोस्ट में, हम Stoffle के लिए पार्सर को

  1. रूबी ऑब्जेक्ट्स को डेकोरेटर पैटर्न से बढ़ाएं: एक व्यावहारिक गाइड रूबी ऑब्जेक्ट्स को डेकोरेटर पैटर्न से बढ़ाएं: एक व्यावहारिक गाइड

    डेकोरेटर डिज़ाइन पैटर्न क्या है? और आप इस पैटर्न का उपयोग अपने रूबी प्रोजेक्ट्स में कैसे कर सकते हैं? डेकोरेटर डिज़ाइन पैटर्न आपको क्लास को बदले बिना नई क्षमताएं जोड़कर एक ऑब्जेक्ट को बढ़ाने में मदद करता है। आइए एक उदाहरण देखें! लॉगिंग और प्रदर्शन इस उदाहरण में हम rest-client जैसे जेम का उपयोग करके

  1. गूगल TCMalloc के साथ रूबी की मेमोरी आवंटन प्रोफाइलिंग गूगल TCMalloc के साथ रूबी की मेमोरी आवंटन प्रोफाइलिंग

    रूबी में मेमोरी आवंटन कैसे काम करता है? रूबी मेमोरी को चंक्स में प्राप्त करता है, जिन्हें पेज कहा जाता है, नए ऑब्जेक्ट्स यहां सहेजे जाते हैं। फिर… जब ये पेज भर जाते हैं, तो अधिक मेमोरी की आवश्यकता होती है। रूबी malloc फंक्शन के साथ ऑपरेटिंग सिस्टम से अधिक मेमोरी का अनुरोध करता है। यह malloc फंक्शन ऑ