রুবি ইন্টারনালসের একটি কুইক ট্যুর চান?
তাহলে আপনি ট്രিট পাওয়ার যাচ্ছেন।
কারণ…
আমরা একসাথে অন্বেষণ করব কীভাবে একটি রুবি অবজেক্ট মেমরিতে লেআউট করা থাকে এবং আপনি কীভাবে ইন্টারনাল ডেটা স্ট্রাকচার ম্যানিপুলেট করে কিছু কুল জিনিস করতে পারেন।
সিট বেল্ট বাঁধুন এবং রুবি ইন্টারপ্রেটারের গভীরতায় যাত্রা করার জন্য প্রস্তুত হোন!
অ্যারের মেমরি লেআউট
যখন আপনি একটি অ্যারে তৈরি করেন, রুবিকে সেটিকে কিছু সিস্টেম মেমরি এবং কিছু মেটাডেটা দিয়ে ব্যাক আপ করতে হয়।
মেটাডেটা অন্তর্ভুক্ত করে:
- অ্যারে সাইজ (আইটেম কাউন্ট)
- অ্যারে ক্যাপাসিটি
- ক্লাস
- অবজেক্ট স্ট্যাটাস (ফ্রোজেন বা নয়)
- মেমরিতে ডেটা কোথায় সংরক্ষিত সেটি নির্দেশকারী একটি পয়েন্টার
যেহেতু মূল রুবি ইন্টারপ্রেটার (MRI) সি (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; } এটি অধিকাংশ রুবি অবজেক্টের কাছে থাকে এবং এতে কিছু জিনিস থাকে যেমন এই অবজেক্টের ক্লাস এবং কিছু বাইনারি ফ্ল্যাগ যা বলে অবজেক্টটি ফ্রোজেন কিনা (এবং অন্যান্য জিনিস যেমন 'tainted' অ্যাট্রিবিউট)।
অন্য কথায়:
RBasic অবজেক্টের জেনেরিক মেটাডেটা ধারণ করে।
তারপর আরেকটি স্ট্রাক্ট আছে, যেটিতে অ্যারের দৈর্ঘ্য (len) থাকে।
ইউনিয়ন এক্সপ্রেশনটি বলছে aux হতে পারে capa (ক্যাপাসিটির জন্য) বা shared। এটি অধিকাংশ অপ্টিমাইজেশন সংক্রান্ত, যা প্যাট শজনেসির এই চমৎকার পোস্টে বিস্তারিত ব্যাখ্যা করা হয়েছে। মেমরি অ্যালোকেশনের দিক থেকে, কম্পাইলার ইউনিয়নের ভিতর সবচেয়ে বড় টাইপ ব্যবহার করবে।
তারপর আছে ptr, যেটিতে আসল Array ডেটা মেমরিতে কোথায় সংরক্ষিত সেটির ঠিকানা থাকে।
এখানে একটা ছবি কীভাবে দেখায় (প্রতিটি সাদে/ধূসর বক্স ৩২-বিট সিস্টেমে ৪ বাইট):

আপনি ObjectSpace মডিউল ব্যবহার করে একটি অবজেক্টের মেমরি সাইজ দেখতে পারেন:
require 'objspace' ObjectSpace.memsize_of([]) # 20
এখন আমরা কিছু মজা করার জন্য প্রস্তুত!
Fiddle: একটি মজার পরীক্ষা
RBasic ৩২-বিট সিস্টেমে সঠিক ৮ বাইট এবং ৬৪-বিট সিস্টেমে ১৬ বাইট। এটা জানলে আমরা Fiddle মডিউল ব্যবহার করে একটি অবজেক্টের র মেমরি বাইট অ্যাক্সেস করতে পারি এবং সেগুলো পরিবর্তন করতে পারি কিছু মজার পরীক্ষার জন্য।
উদাহরণস্বরূপ:
আমরা একটি সিঙ্গেল বিট টগল করে ফ্রোজেন স্ট্যাটাস পরিবর্তন করতে পারি।
এটিই মূলত freeze মেথডটি করে, কিন্তু লক্ষ্য করুন কত কোনো unfreeze মেথড নেই।
চলুন শুধু মজার জন্য এটি ইমপ্লিমেন্ট করি!
প্রথম, Fiddle মডিউল (রুবি স্ট্যান্ডার্ড লাইব্রেরির অংশ) রিকওয়ায়ার করি এবং একটি ফ্রোজেন স্ট্রিং তৈরি করি।
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 ভ্যালুর ২য় বাইটকে বোঝায় (যেটি মোট ৪ বাইট تشکیل করে)।
তারপর আমরা ^= ব্যবহার করি যা "XOR" (এক্সক্লুসিভ OR) অপারেটর এবং সেই বিটটি ফ্লিপ করে।
আমরা এটি করি কারণ flags-এর ভিন্ন বিটগুলো ভিন্ন অর্থ বহন করে এবং আমরা অন্য কিছু পরিবর্তন করছি না।
আপনি যদি আমার রুবি ট্রিকস পোস্ট পড়েছেন তবে আপনি এটা আগে দেখেছেন হতে পারে, কিন্তু এখন আপনি জানেন এটি কীভাবে কাজ করে 🙂
আরেকটি জিনিস আপনি চেষ্টা করতে পারেন অ্যারের দৈর্ঘ্য পরিবর্তন করে এবং অ্যারে প্রিন্ট করুন।
আপনি দেখবেন কীভাবে অ্যারে ছোট হয়ে যাচ্ছে!
আপনি ক্লাসও পরিবর্তন করতে পারেন একটি Array-কে মনে করাতে যে সেটি একটি String…
উপসংহার
আপনি রুবি হুডের নিচে কীভাবে কাজ করে সেটি সম্পর্কে কিছুটা শিখেছেন। রুবি অবজেক্টের জন্য মেমরি কীভাবে লেআউট করা থাকে এবং আপনি কীভাবে Fiddle মডিউল ব্যবহার করে সেটির সাথে খেলতে পারেন।
আপনার вероятно আসল অ্যাপ্লিকেশনে এইভাবে Fiddle ব্যবহার করা উচিত নয়, কিন্তু এক্সপেরিমেন্ট করার জন্য এটি মজার।
এই পোস্ট শেয়ার করা না ভুলেন যাতে আরও মানুষ এটা দেখতে পারে 🙂