কম্পিউটার টিউটোরিয়াল

রুবি GC মাস্টার: অপ্টিমাল পারফরম্যান্সের জন্য প্র্যাকটিক্যাল টিউনিং

আমরা আবিষ্কার করেছি নিচের পোস্টটি নেট বেরকোপেকের ২০১৭ সালের একটি আর্টিকেল 'Understanding Ruby GC through GC.stat'その上 ভিত্তি করে তৈরি। मालूम হয় এই আর্টিকেলের অংশগুলো প্লেজিয়ারাইজড, যা আমরা পাবলিশ করার আগে জানতাম না। আমরা আমাদের সকল আর্টিকেল প্লেজিয়ারিজম টুল দিয়ে চেক করি পাবলিশ করার আগে, কিন্তু এটা এটা ক্যাচ করতে পারলো না। নেট এবং আমাদের পাঠকদের প্রতি আমরা গভীর ক্ষমা প্রকাশ করছি এই অনিচ্ছাকৃত ভুলের জন্য।

রুবি গার্বেজ কালেকশন কীভাবে কাজ করে সেটি বুঝতে হলে আপনার অ্যাপের পারফরম্যান্সের ওপর পুরো কন্ট্রোল রাখতে পারবেন।

এই পোস্টে, আমরা রুবিতে গার্বেজ কালেকশন ইমপ্লিমেন্ট ও কাস্টমাইজ করার উপায়ে গভীরে যাব।

চলুন শুরু করি!

রুবি গার্বেজ কালেক্টর মডিউল

রুবি গার্বেজ কালেক্টর মডিউল হলো রুবির মার্ক অ্যান্ড সুইপ গার্বেজ কালেকশন মেকানিজমের ইন্টারফেস।

যদিও এটি প্রয়োজনে ব্যাকগ্রাউন্ডে স্বয়ংক্রিয়ভাবে চলে, GC মডিউল আপনাকে GC ম্যানুয়ালি কল করার অনুমতি দেয় যখনই দরকার এবং গার্বেজ কালেকশন সাইকেল কীভাবে চলছে সে সম্পর্কে ইনসাইট পাওয়া যায়। মডিউলটি কিছু প্যারামিটার প্রদান করে যেগুলো আপনি পরিবর্তন করে পারফরম্যান্স মডারেট করতে পারেন।

এই মডিউলের সবচেয়ে কমন ব্যবহার হওয়া মেথডগুলো:

  • start/garbage_collect: এই মেথড ম্যানুয়ালি গার্বেজ কালেকশন সাইকেল শুরু করে।
  • enable/disable: এই মেথডগুলো অটোমেটিক গার্বেজ কালেকশন সাইকেল ইনএবল বা ডিজএবল করে। সেগুলো একটি বুলিয়ান ভ্যালু রিটার্ন করে আপারেশন সাকসেসফুল কিনা বোঝাতে।
  • stat: এই মেথড কী এবং ভ্যালুর একটি লিস্ট প্রদান করে যা GC মডিউলের পারফরম্যান্স বর্ণনা করে। 우리는 পরবর্তী সেকশনে এই মেট্রিক্সগুলোকে ডিটেইলসhibangে দেখব।

রুবি গার্বেজ কালেক্টর প্যারামিটার বোঝা

রুবির GC ইন্টারন্যালি কীভাবে কাজ করে সেটি বুঝতে, GC মডিউলের মেট্রিক্স দেখি। ফ্রেশলি বুট করা irb-এ নিচের কমান্ড রান করুন:

puts GC.stat

আপনি লক্ষ্য করবেন আপনার স্ক্রিনে অনেক নম্বর পপ আপ হয়েছে, যা এমন দেখাবে:

{
  :count=>12,
  :heap_allocated_pages=>49,
  :heap_sorted_length=>49,
  :heap_allocatable_pages=>0,
  :heap_available_slots=>19975,
  :heap_live_slots=>19099,
  :heap_free_slots=>876,
  :heap_final_slots=>0,
  :heap_marked_slots=>16659,
  :heap_eden_pages=>49,
  :heap_tomb_pages=>0,
  :total_allocated_pages=>49,
  :total_freed_pages=>0,
  :total_allocated_objects=>66358,
  :total_freed_objects=>47259,
  :malloc_increase_bytes=>16216,
  :malloc_increase_bytes_limit=>16777216,
  :minor_gc_count=>10,
  :major_gc_count=>2,
  :remembered_wb_unprotected_objects=>191,
  :remembered_wb_unprotected_objects_limit=>312,
  :old_objects=>16024,
  :old_objects_limit=>23556,
  :oldmalloc_increase_bytes=>158824,
  :oldmalloc_increase_bytes_limit=>16777216
}

এইখানে রানটাইমে গার্বেজ কালেকশন কীভাবে হচ্ছে সে সম্পর্কে সকল ইনফরমেশন আছে। আসুন প্রতিটি নম্বরকে ডিটেইলসhibangে যাচাই করি।

রুবি গার্বেজ কালেক্টরে কাউন্ট

আমরা এই কীগুলো বর্ণনা করে শুরু করব:

{
  :count=>12,
  ...
  :minor_gc_count=>10,
  :major_gc_count=>2,
}

এগুলো GC কাউন্ট, এবং এগুলো সহজ কথা বলে। minor_gc_count এবং major_gc_count হলো প্রতিটি টাইপের গার্বেজ কালেকশন রানের কাউন্ট।

রুবিতে দুটি ধরনের গার্বেজ কালেকশন আছে।

Minor GC বলতে একটি গার্বেজ কালেকশন অটেম্প্টকে বোঝায় যা শুধু নতুন অবজেক্টগুলোকে গার্বেজ কালেক্ট করার চেষ্টা করে, অর্থাৎ সেগুলো তিন বা ততোধিক গার্বেজ কালেকশন সাইকেল সারভাইভ করেছে।

অন্যদিকে, Major GC হলো একটি গার্বেজ কালেকশন অটেম্প্ট যা সব অবজেক্টকে গার্বেজ কালেক্ট করার চেষ্টা করে, এমন অবজেক্টও যেগুলো তিনটির বেশি গার্বেজ কালেকশন সাইকেল সারভাইভ করেছে। count হলো minor_gc_count এবং major_gc_count-এর যোগফল।

GC কাউন্ট ট্র্যাক করা কিছু কারণে হেল্পফুল হতে পারে। আপনি বের করতে পারবেন কোনো নির্দিষ্ট জব বা প্রসেস সবসময় GC ট্রিগার করছে কিনা এবং কতবার ট্রিগার করছে। মাল্টিথ্রেডেড অ্যাপ্লিকেশনের কেসে এটি ১০০% একুরেট নাও হতে পারে, কিন্তু আপনার মেমরি কোথায় লিক হচ্ছে সেটি বের করার জন্য এটি একটি ভালো স্টার্টিং পয়েন্ট।

হিপ নম্বর: স্লটস ও পেজ

এখন কথা বলি এই কীগুলো, যাকে হিপ নম্বর-ও বলা হয়:

{
  # পেজ নম্বর
  :heap_allocated_pages=>49,
  :heap_sorted_length=>49,
  :heap_allocatable_pages=>0,
  # স্লটস
  :heap_available_slots=>19975,
  :heap_live_slots=>19099,
  :heap_free_slots=>876,
  :heap_final_slots=>0,
  :heap_marked_slots=>16659,
  # Eden এবং Tomb পেজ
  :heap_eden_pages=>49,
  :heap_tomb_pages=>0,
}

আমরা যেসব হিপের কথা বলছি সেটি একটি C ডেটা স্ট্রাকচার। এতে বর্তমানে লাইভ রুবি অবজেক্টের সকল রেফারেন্স থাকে। একটি হিপ পেজ মেমরি স্লটস দিয়ে কমপোজড, এবং প্রতিটি স্লট শুধু একটি লাইভ রুবি অবজেক্টের ইনফরমেশন ধারণ করে:

  • heap_allocated_pages হলো বর্তমানে অ্যালোকেট করা হিপ পেজের সংখ্যা। এই পেজগুলো সম্পূর্ণ খালি, সম্পূর্ণ ভরা, বা আংশিকভাবে ভরা হতে পারে।
  • heap_sorted_length হলো হিপ যে আসল সাইজ মেমরিতে আকরণ করেছে এবং এটি heap_allocated_pages-এর থেকে ভিন্ন, কারণ লেন্থ হলো হিপ পেজগুলোর length একসাথে জোড়া, তাদের count নয়। যদি আপনি প্রাথমিকভাবে ১০টি পেজ অ্যালোকেট করেন এবং তারপর সেটের মাঝপথ থেকে একটি ফ্রি করেন, তবে আপনার heap_allocated_pages হবে ৯, কিন্তু heap_sorted_length এখনো ১০ থাকবে।
  • শেষে, heap_allocatable_pages হলো সেসব হিপের কাউন্ট যা রুবি বর্তমানে ওন্ড করে এবং প্রয়োজনে ব্যবহার করা যাবে।

এখন স্লটসের কথা:

  • heap_available_slots হলো হিপ পেজগুলোর মোট উপলব্ধ স্লট।
  • heap_live_slots হলো মেমরিতে লাইভ অবজেক্টের সংখ্যা।
  • heap_free_slots হলো অ্যালোকেটেড হিপ পেজগুলোর খালি স্লট।
  • heap_final_slots হলো সেসব স্লটের কাউন্ট যাদের অবজেক্টের সাথে ফাইনালাইজার আট্যাচড। ফাইনালাইজার হলো প্রক যা একটি অবজেক্ট ফ্রি হলে চলে, OOPS-এ ডেস্ট্রাক্টরের মতো।
  • heap_marked_slots হলো পুরনো অবজেক্টের কাউন্ট (অর্থাৎ যেসব অবজেক্ট ৩টি GC সাইকেলের চেয়ে বেশি সময় থেকে আছে) এবং রাইট-ব্যারিয়ার আনপ্রটেক্টেড অবজেক্ট।

তারপর আছে tomb_pages এবং eden_pages।

tomb_pages হলো সেসব পেজের কাউন্ট যেগুলো কোনো লাইভ অবজেক্ট ধারণ করে না। এই পেজগুলো समयের সাথে রুবি দ্বারা অপারেটিং সিস্টেমে ফেরত দেয়া হয়।

অন্যদিকে, eden_pages হলো সেসব পেজের কাউন্ট যেগুলো কমপক্ষে একটি লাইভ অবজেক্ট ধারণ করে, তাই সেগুলো অপারেটিং সিস্টেমে ফেরত দেওয়া যায় না।

মেট্রিক heap_free_slots মনিটর করার কথা বিবেচনা করুন যদি আপনার অ্যাপ্লিকেশনে মেমরি ব্লোট ইস্যু থাকে।

বেশি ফ্রি স্লট (২৫০,০০০ এর বেশি) সাধারণত ইঙ্গিত করে যে আপনার হাতের নিকট কয়েকটি কন্ট্রোলার অ্যাকশন আছে যা একসাথে অনেক অবজেক্ট অ্যালোকেট করে এবং তারপর সেগুলো ফ্রি করে। এটি আপনার রানিং রুবি প্রসেসের সাইজ স্থায়ীভাবে ফুলিয়ে দিতে পারে।

কিউমুলেটিভ নম্বর

{
  :total_allocated_pages=>49,
  :total_freed_pages=>0,
  :total_allocated_objects=>66358,
  :total_freed_objects=>47259,
}

এই নম্বরগুলো কিউমুলেটিভ বা অ্যাডিটিভ প্রক্রিয়ার প্রকৃতির পুরো প্রসেসের লাইফটাইমের জন্য। সেগুলো GC দ্বারা কখনও রিসেট হয় না এবং টেকনিক্যালি কমতে পারে না। চারটি নম্বরই স্বয়ংক্রিয়ভাবে বোঝা যায়।

গার্বেজ কালেকশন থ্রেশহোল্ড

এই নম্বরগুলো বুঝতে, প্রথমে বুঝতে হবে GC কখন ট্রিগার হয়:

{
  :malloc_increase_bytes=>16216,
  :malloc_increase_bytes_limit=>16777216,
  :remembered_wb_unprotected_objects=>191,
  :remembered_wb_unprotected_objects_limit=>312,
  :old_objects=>16024,
  :old_objects_limit=>23556,
  :oldmalloc_increase_bytes=>158824,
  :oldmalloc_increase_bytes_limit=>16777216
}

সাধারণ ধারণা বিরুদ্ধে যে GC রান ফিক্সড ইন্টারভালে হয়, GC রানগুলো ট্রিগার হয় যখন রুবি মেমরি স্পেসের অভাব অনুভব করতে শুরু করে। Minor GC হয় যখন রুবি free_slots-এ অভাব অনুভব করে।

যদি মাইনর GC রানের পরেও রুবি free_slots-এ কম পায় — অথবা oldmalloc, malloc, old object count, অথবা shady/রাইট-ব্যারিয়ার-আনপ্রটেক্টেড কাউন্টের থ্রেশহোল্ড অতিক্রম হয় — তবে মেজর GC রান ট্রিগার হয়। gc.stat-এর উপরের অংশ এই থ্রেশহোল্ডের ভ্যালু দেখাচ্ছে।

malloc_increase_bytes বলতে হিপের বাইরে অ্যালোকেট করা মেমরির পরিমাণকে বোঝায়। যখন একটি অবজেক্টের সাইজ স্ট্যান্ডার্ড মেমরি স্লটের সাইজ — মনে করুন ৪০ বাইট — অতিক্রম করে, রুবি সেটির জন্য অন্য জায়গায় malloc করে কিছু স্পেস। যখন টোটাল এক্সট্রা অ্যালোকেটেড স্পেস malloc_increase_bytes_limit অতিক্রম করে, একটি মেজর GC ট্রিগার হয়।

oldmalloc_increase_bytes পুরনো অবজেক্টের জন্য একই ধরনের থ্রেশহোল্ড। old_objects হলো old হিসেবে মার্ক করা অবজেক্ট স্লটের কাউন্ট। যখন সংখ্যা old_objects_limit অতিক্রম করে, মেজর GC ট্রিগার হয়।

remembered_wb_unprotected_objects হলো সেসব অবজেক্টের টোটাল কাউন্ট যেগুলো রাইট-ব্যারিয়ার দ্বারা প্রটেক্টেড নয় এবং রিমেম্বার্ড সেট-এর অংশ।

রাইট-ব্যারিয়ার হলো রুবি রানটাইম এবং এর অবজেক্টের মধ্যে একটি ইন্টারফেস, যা ইন্টারপ্রেটারকে অবজেক্টের রেফারেন্স ট্র্যাক করতে দেয় সেগুলো তৈরি होते সাথে সাথে।

C-এক্সটেনশন রাইট-ব্যারিয়ার ব্যবহার না করে অবজেক্টের নতুন রেফারেন্স তৈরি করতে পারে, সেক্ষেত্রে অবজেক্টগুলো shady বা রাইট-ব্যারিয়ার আনপ্রটেক্টেড হিসেবে মার্ক হয়। রিমেম্বার্ড সেট হলো সপ্লাই পুরনো অবজেক্টের লিস্ট যাদের কমপক্ষে একটি রেফারেন্স আছে নতুন অবজেক্টের প্রতি।

রুবি গার্বেজ কালেকশন পারফরম্যান্স কাস্টমাইজ করা

এখন আপনি বুঝতে পারছেন রুবি GC কীভাবে আপনার অ্যাপ্লিকেশনের মেমরি ম্যানেজ করে, তখন GC-এর বিহেভিয়ার কাস্টমাইজ করার অপশনগুলো দেখার পালা।

এনভায়রনমেন্ট ভেরিয়েবলগুলো যা আপনি ব্যবহার করতে পারেন রুবি GC-এর পারফরম্যান্স মডারেট করতে এবং এর মাধ্যমে আপনার অ্যাপ্লিকেশনের পারফরম্যান্স উন্নত করতে:

RUBY_GC_HEAP_INIT_SLOTS
RUBY_GC_HEAP_FREE_SLOTS
RUBY_GC_HEAP_GROWTH_FACTOR
RUBY_GC_HEAP_GROWTH_MAX_SLOTS
RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR
and other variables

গুরুত্বপূর্ণ প্যারামিটারগুলো একে একে আলোচনা করি:

  • RUBY_GC_HEAP_INIT_SLOTS: রুবি হিপে প্রাথমিক স্লটের সংখ্যা ডিফাইন করে এবং ডিফল্টভাবে ১০০০০ সেট থাকে। আপনি এই প্যারামিটার পরিবর্তন করতে চাইতে পারেন যদি আপনি নিশ্চিত হন আপনার অ্যাপ প্রাথমিকভাবে অধিকাংশ অবজেক্ট অ্যালোকেট করবে।
  • RUBY_GC_HEAP_FREE_SLOTS: একটি GC সাইকেলের ঠিক পর কমপক্ষে কতটুকু ফ্রি স্লট উপলব্ধ থাকবে সেটি কন্ট্রোল করে। এর ডিফল্ট ভ্যালু ৪০৯৬। এই ভ্যালু শুধু একবার রানটাইমে প্রথম হিপ গ্রোথের সময় ব্যবহার হয়।
  • RUBY_GC_HEAP_GROWTH_FACTOR: রুবি ইন্টারপ্রেটারের উপলব্ধ হিপ কত গুণ বাড়বে সেটি। ডিফল্ট ভ্যালু ১.৮। এটিকে পরিবর্তন করলে খুব কিছু বদলে না, কারণ রুবি ইতিমধ্যে হিপ গ্রোথে অ্যাগ্রেসিভ। এটি কমালেও বড় পার্থক্য হবে না কারণ মডার্ন ইন্টারপ্রেটারে হিপ অন-ডিমান্ড অ্যালোকেট হয়।
  • RUBY_GC_HEAP_GROWTH_MAX_SLOTS: রুবি একবারে হিপ স্পেসে কতটুকু স্লট যোগ করতে পারবে তার ম্যাক্সিমাম। ডিফল্ট ভ্যালু ০, যা মানে কোনো লিমিট নেই। যদি আপনার অ্যাপ লাইফটাইমে মিলিয়ন অবজেক্ট অ্যালোকেট করতে হয়, তবে আপনি এই প্যারামিটারের ওপর একটি ক্যাপ দিতে চাইতে পারেন। যাইহোক, এটের আপনার অ্যাপের GC টাইমের ওপর খুব কম প্রভাব থাকবে।
  • RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR ইন্টারপ্রেটারকে বাধ্য করে একটি মেজর GC সাইকেল চালানোর জন্য যখন মেমরিতে টোটাল পুরনো অবজেক্টের সংখ্যা = এই নম্বর x শেষ GC সাইকেলের পর মেমরিতে পুরনো অবজেক্টের সংখ্যা। আপনি এই নম্বর বাড়াতে চাইতে পারেন যদি আপনি মনে করেন আপনার অনেক অবজেক্ট পুরনো জেনারেশনে ঢুকলে আনইউজড হয়ে যাবে। যাইহোক, এটি খুব কম প্রয়োজনীয়।
  • RUBY_GC_MALLOC_LIMIT হলো নিউ জেনারেশনের জন্য malloc কলের মিনিমাম লিমিট। এর ডিফল্ট ভ্যালু ১৬ MB। RUBY_GC_MALLOC_LIMIT_MAX হলো সেইম malloc কলের ম্যাক্সিমাম লিমিট। এর ডিফল্ট ভ্যালু ৩২ MB। আপনি এই দুটি লিমিট বাড়াতে চাইতে পারেন যদি আপনার অ্যাপ্লিকেশন গড়ের চেয়ে বেশি মেমরি ব্যবহার করে। যাইহোক, সাবধান থাকুন এগুলো খুব বেশি বাড়ালে না। অন্যথায়, সেগুলো হাইয়ার পিক মেমরি কনসাম্পশনে লিড করতে পারে। সবসময় এই লিমিট ইনক্রিমেন্টালি বাড়ান — ৪ বা ৮ MB দিয়ে।
  • RUBY_GC_MALLOC_LIMIT_GROWTH_FACTOR হলো নিউ জেনারেশনের malloc লিমিটের গ্রোথ ফ্যাক্টর। এর ডিফল্ট ভ্যালু ১.৪। আপনি এই নম্বর বাড়াতে বিবেচনা করতে পারেন যদি আপনার অ্যাপ মেমরি চানকে বা পুরো একসাথে না করে আলাদা আলাদা অ্যালোকেট করে।
  • একইভাবে, RUBY_GC_OLDMALLOC_LIMIT এবং RUBY_GC_OLDMALLOC_LIMIT_MAX হলো পুরনো জেনারেশনের জন্য মিনিমাম এবং ম্যাক্সিমাম malloc লিমিট। এই প্যারামিটারগুলোর ডিফল্ট ভ্যালু ১৬ MB এবং ১২৮ MB।
  • RUBY_GC_OLDMALLOC_LIMIT_GROWTH_FACTOR হলো এই লিমিটের গ্রোথ ফ্যাক্টর। এর ডিফল্ট ভ্যালু ১.২। আপনি নিউ জেনারেশন লিমিটের সাথে এগুলো পরিবর্তন করতে পারেন ম্যাক্সিমাম ইফেক্টের জন্য।

রুবিতে গার্বেজ কালেকশন ফাইন-টিউনিং

আমরা GC মডিউল কাস্টমাইজ করার কিছু কমন ও সহজ পদ্ধতি আলোচনা করেছি যা আপনার অ্যাপ্লিকেশনের সামগ্রিক পারফরম্যান্স উন্নত করতে সাহায্য করতে পারে। যাইহোক, এই টুইকগুলো সব কেসে কাজ নাও করতে পারে। আপনাকে আপনার অ্যাপের মেমরি ইউজেজ প্যাটার্ন বুঝতে হবে সিদ্ধান্ত নেওয়ার আগে কী কাস্টমাইজ করবেন।

অন্যদিকে, আপনি একটি অটোমেটেড টেস্ট চালাতে পারেন যা আপনার জন্য এই প্যারামিটারগুলোর সেরা ভ্যালু খুঁজে বের করবে। TuneMyGC-এর মতো টুল আপনার এনভায়রনমেন্ট ভেরিয়েবলগুলোর সেরা সেট খুঁজে বের করার জন্য খুব সহজ।

অবশ্যই GC প্যারামিটারগুলো দেখুন যদি আপনার অ্যাপ্লিকেশন অদ্ভুতভাবে বিহেভ করছে। এখানে একটি ছোট পরিবর্তন আপনার অ্যাপের মেমরি কনসাম্পশন অনেক হ্রাস করতে পারে এবং মেমরি ব্লোট প্রিয়েন্ট করতে পারে।

আশা করি এই আর্টিকেল আপনাকে একটি ভালো ধারণা দিয়েছে রুবি গার্বেজ কালেকশন মডিউল কাস্টমাইজ করার সময় কী খুঁজে বের করতে হবে। আরো ইন্ট্রোডাক্টরি কন্টেন্টের জন্য, Introduction to Garbage Collection Part I এবং Part II চেক আউট করুন।

হ্যাপি কোডিং!

  1. রুবি ২.৬-এ ৯টি গুরুত্বপূর্ণ উন্নতির অন্বেষণ

  2. রুবি ২.৫ পারফরম্যান্স বूस্ট: ৭২% দ্রুত স্ট্রিং ইন্টারপোলেশন, ৫০% দ্রুত Enumerable মেথড

  3. রুবিতে লিঙ্কড লিস্টে দক্ষতা অর্জন: একটি ব্যাবহারিক গাইড

  4. রুবি দিয়ে ব্যাবহারিক গ্রাফ থিওরি মास্টার করুন