একটি মেমরি ফাঁস একটি অনিচ্ছাকৃত, অনিয়ন্ত্রিত, এবং সীমাহীন বৃদ্ধি মেমরি ব্যবহার. যতই ছোট হোক না কেন, অবশেষে, একটি লিক আপনার প্রক্রিয়ার মেমরি ফুরিয়ে যাবে এবং ক্র্যাশ করবে। এমনকি যদি আপনি এই ক্র্যাশ এড়াতে আপনার অ্যাপটি পর্যায়ক্রমে পুনরায় চালু করেন (কোন রায় নেই, আমি এটি করেছি!), তবুও আপনি মেমরি লিকের কার্যকারিতার প্রভাব ভোগ করেন।
এই পোস্টে, মেমরি ফাঁসের উপর একটি দুই-অংশের সিরিজের প্রথম, আমরা রুবি কীভাবে মেমরি পরিচালনা করে, কীভাবে আবর্জনা সংগ্রহ (GC) কাজ করে এবং কীভাবে একটি লিক খুঁজে বের করতে হয় তা দেখে শুরু করব৷
দ্বিতীয় অংশে, আমরা ফাঁস ট্র্যাক করার জন্য আরও গভীরে ডুব দেব।
চলুন শুরু করা যাক!
রুবি মেমরি ম্যানেজমেন্ট
রুবি বস্তু স্তূপে সংরক্ষণ করা হয়, এবং প্রতিটি বস্তু স্তূপে একটি স্লট পূরণ করে।
রুবি 3.1-এর আগে, হিপের সমস্ত স্লট একই আকারের ছিল — 40 বাইট, সঠিক হতে হবে। একটি স্লটে মাপসই করার জন্য খুব বড় বস্তুগুলি স্তূপের বাইরে সংরক্ষণ করা হয়েছিল৷ প্রতিটি স্লটে একটি রেফারেন্স অন্তর্ভুক্ত ছিল যেখানে বস্তুগুলি সরানো হয়েছিল৷
৷
রুবি 3.1-এ, String-এর জন্য পরিবর্তনশীল প্রস্থ বরাদ্দ বস্তু একত্রিত করা হয়েছিল। শীঘ্রই, পরিবর্তনশীল প্রস্থ বরাদ্দ করা হবে অ্যালবজেক্ট প্রকারের জন্য আদর্শ।
পরিবর্তনশীল প্রস্থ বরাদ্দের লক্ষ্য ক্যাচেলোক্যালিটি উন্নত করার মাধ্যমে কর্মক্ষমতা উন্নত করা — একটি বস্তুর সমস্ত তথ্য দুটি মেমরি অবস্থানের পরিবর্তে এক জায়গায় সংরক্ষণ করা হবে।
এটি মেমরি পরিচালনার (কিছু অংশ) সরলীকরণ করা উচিত। এই মুহুর্তে, সেখানে দুটি 'স্তূপ' আছে:
- রুবি হিপ (বা GC হিপ) যা ছোট রুবি বস্তু সঞ্চয় করে।
- C স্তূপ (বা malloc/ক্ষণস্থায়ী স্তূপ) যা বড় বস্তু সঞ্চয় করে।
একবার পরিবর্তনশীল প্রস্থ বরাদ্দ করা আদর্শ হয়ে গেলে, পরবর্তী হিপের প্রয়োজন হবে না।
হিপটি একটি প্রদত্ত আকারে শুরু হয় (ডিফল্টরূপে 10,000 স্লট) এবং বস্তুগুলি তৈরি হওয়ার সাথে সাথে বিনামূল্যে স্লটে বরাদ্দ করা হয়। যখন রুবি একটি বস্তু তৈরি করার চেষ্টা করে এবং সেখানে কোনো বিনামূল্যের স্লট উপলব্ধ থাকে না, তখন গারবেজ কালেকশন (GC) কিছু বিনামূল্যের স্লট উপলব্ধ করে।
GC-এর পরে যদি খুব কম ফ্রি স্লট থাকে, তবে স্তূপটি প্রসারিত করা হবে (একটু পরে এই বিষয়ে আরও)।
পরিবেশের ভেরিয়েবলের পাশাপাশি আপনি যে বিষয়গুলি নিয়ন্ত্রণ করতে পারেন তা এখানে রয়েছে:
- স্তূপের প্রাথমিক আকার -
RUBY_GC_HEAP_INIT_SLOTS - GC হওয়ার পরে বিনামূল্যের স্লটের সংখ্যা যা পাওয়া উচিত -
RUBY_GC_HEAP_FREE_SLOTS - গূপের পরিমাণ -
RUBY_GC_HEAP_GROWTH_FACTORদ্বারা প্রসারিত হয়
রুবিতে আবর্জনা সংগ্রহ
রুবিতে আবর্জনা সংগ্রহ 'বিশ্বকে থামিয়ে দেয়' — GC ঘটলে অন্য কোনো প্রক্রিয়া ঘটে না। রুবিতে আবর্জনা সংগ্রহ (২.১ থেকে) এছাড়াও প্রজন্মগত , মানে আবর্জনা সংগ্রহকারীর দুটি মোড রয়েছে:
- মাইনর জিসি - 'তরুণ' বস্তুগুলি পরিদর্শন করে (সম্প্রতি তৈরি করা বস্তু)
- মেজর জিসি - 'পুরাতন' বস্তুর পাশাপাশি 'তরুণ' বস্তু (সমস্ত) পরিদর্শন করে বস্তু)
দ্রষ্টব্য :একটি 'পুরানো' বস্তু বেঁচে আছে 3 GC রান, বড় বা ছোট।
যখন স্তূপটি পূর্ণ হয়, তখন ছোটখাট GC প্রথমে আহ্বান করা হয়। যদি এটি সীমার নিচে পর্যাপ্ত স্লট খালি করতে না পারে, তাহলে প্রধান GC আহ্বান করা হবে। তবেই, যদি এখনও পর্যাপ্ত বিনামূল্যের স্লট না থাকে, তাহলে গাদাটি প্রসারিত হবে।
মেজর GC ছোট GC থেকে বেশি ব্যয়বহুল কারণ এটি আরও বেশি বস্তুর দিকে নজর দেয়।
জেনারেশনাল জিসি কেন বেশি পারফরম্যান্সের পিছনে তত্ত্ব হল যে বস্তুগতভাবে দুটি বিভাগে পড়ে:
- বরাদ্দকৃত বস্তু এবং তারপর দ্রুত সুযোগের বাইরে চলে যায়। একটি Rails অ্যাপে, একটি পৃষ্ঠা রেন্ডার করার জন্য DB থেকে আনা মডেলগুলি যখন অনুরোধ শেষ হবে তখন সুযোগের বাইরে চলে যাবে৷
- বস্তু যা বরাদ্দ করা হয় এবং দীর্ঘ সময় ধরে রাখা হয়। একটি অ্যাপের সারাজীবন ধরে ক্লাস এবং ক্যাশে এখনও ব্যবহার করা হতে পারে।
মেজর GC ছোট GC-এর পরেও চলবে যদি পুরানো বস্তুর সংখ্যা নির্দিষ্ট থ্রেশহোল্ডের উপরে হয়, এমনকি পর্যাপ্ত ফ্রি স্লট থাকলেও। স্তূপের আকার বাড়ার সাথে সাথে এটি সীমা বৃদ্ধি পায় এবং RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR দ্বারা নিয়ন্ত্রিত হতে পারে পরিবেশ পরিবর্তনশীল।
যখন আপনার একটি ফুটো হয়, তখন আপনি এমন বস্তু তৈরি করেন যা পরিষ্কার করা যায় না — আরও বেশি করে old বস্তু এর মানে হল যে বড় (ব্যয়বহুল) GC যতটা উচিত তার চেয়ে অনেক বেশি বার চালাবে। যেহেতু GC যখন চলছে তখন আর কিছুই চলে না, তাই এই সময়টা আপনি নষ্ট করেন।
মেমরি লেআউট এবং রুবিতে আবর্জনা সংগ্রাহক সম্পর্কে আরও পড়ার জন্য আমি এই নিবন্ধের শেষে কিছু লিঙ্ক রেখেছি।
রুবিতে মেমরি লিক দেখতে কেমন লাগে?
আপনি যেকোনো ইউনিক্স সিস্টেমে উপলব্ধ সহজ সরঞ্জাম ব্যবহার করে একটি মেমরি লিক দেখতে পারেন। একটি উদাহরণ হিসাবে নিম্নলিখিত কোড নিন.
এই কোড 'লিক' বলাটা একটু অন্যায্য—এটা শুধুই ফাঁস! —কিন্তু এটা আমাদের উদ্দেশ্য পূরণ করে।
আমরা এই প্রোগ্রামটিকে একটি টার্মিনালে এবং watch চালিয়ে কমান্ড লাইন থেকে খুব সহজভাবে লিক পর্যবেক্ষণ করতে পারি। -ps এর সাথে সময়ের সাথে সাথে মেমরি বৃদ্ধি পায় .
pgrep -f "ruby ./leaky.rb" আমাদের জন্য প্রক্রিয়া আইডি খুঁজে বের করে, যাতে আমরা ps সীমাবদ্ধ করতে পারি শুধুমাত্র আমাদের আগ্রহের প্রক্রিয়ায় আউটপুট। আপনি হয়তো অনুমান করতে পারবেন, এটি grep এর মত প্রক্রিয়ার জন্য।
watch টুল আমাদের টার্মিনালের মধ্যে একটি লাইভ ড্যাশবোর্ড প্রদান করে একটি প্রদত্ত কমান্ডের আউটপুট পোল করতে এবং সেটিকে আপডেট করার অনুমতি দেয়৷
আপনি এইরকম আউটপুট পাবেন, যা প্রতি কয়েক সেকেন্ডে আপডেট হয়।
আপনার %MEM দেখতে হবে এবং RSS বৃদ্ধি তারা হল:
%MEM- হোস্ট মেশিনে মেমরির শতাংশ হিসাবে প্রক্রিয়াটি যে পরিমাণ মেমরি ব্যবহার করে।RSS(রেসিডেন্ট সেট সাইজ) - প্রসেসটি বাইটে যে পরিমাণ RAM ব্যবহার করে।
এই মৌলিক OS-শুধু তথ্য আপনার যদি লিক থাকে তা চিহ্নিত করার জন্য যথেষ্ট — যদি মেমরি ক্রমাগত বাড়তে থাকে, তার মানে আপনি করবেন!
গারবেজ কালেক্টর মডিউল দিয়ে রুবি লিকস খুঁজুন
আমরা GC দিয়ে রুবি কোডের মধ্যেই লিক সনাক্ত করতে পারি মডিউল।
GC.stat পদ্ধতি অনেক দরকারী তথ্য সহ একটি হ্যাশ ফেরত দেবে। এখানে, আমরা :heap_live_slots এ আগ্রহী , যা ব্যবহারে থাকা স্তূপের স্লটের সংখ্যা। এটি :heap_free_slots এর বিপরীত .লুপের শেষে, আমরা একটি প্রধান GC ফোর্স করি এবং ব্যবহৃত স্লটের সংখ্যা, অর্থাৎ, GC-এর পরে থাকা বস্তুর সংখ্যা প্রিন্ট আউট করি।
আমরা যখন আমাদের ছোট প্রোগ্রাম চালাই, আমরা এই বৃদ্ধি বিজ্ঞাপন অসীম দেখতে. আমাদের একটি ফুটো আছে! আমরা GC.stat(:old_objects)ও ব্যবহার করতে পারতাম একই প্রভাবে।
যখন GC মডিউল if দেখতে ব্যবহার করা যেতে পারে আমাদের একটি ফাঁস আছে এবং (যদি আপনি আপনার puts দিয়ে পুনরায় স্মার্ট হন বিবৃতি) যেখানে লিক ঘটতে পারে, আমরা ObjectSpace দিয়ে লিক হতে পারে এমন বস্তুর ধরন দেখতে পারি মডিউল।
ObjectSpace.count_objects পদ্ধতি লাইভ বস্তুর গণনা সহ একটি হ্যাশ প্রদান করে। T_STRING , উদাহরণস্বরূপ, স্ট্রিং সংখ্যা লাইভ ইমেমরি. আমাদের বরং লিকি প্রোগ্রামের জন্য, এই মান প্রতিটি লুপের সাথে বৃদ্ধি পায়, এমনকি GC এর পরেও। আমরা দেখতে পাচ্ছি যে আমরা স্ট্রিং অবজেক্ট লিক করছি।
অ্যাপসিগন্যালের মাধ্যমে উৎপাদনে অ্যাপ্লিকেশন পারফরম্যান্স মনিটরিং
ps এর সাথে খেলার সময় এবং GC খেলনা প্রকল্পগুলির জন্য একটি বুদ্ধিমান রুট হতে পারে —এগুলি ব্যবহার করার জন্য মজাদার এবং তথ্যপূর্ণও! — আমি না করব প্রোডাকশন অ্যাপে আপনার মেমরি লিক শনাক্তকরণ সমাধান হিসাবে তাদের সুপারিশ করুন।
এখানে আপনি একটি অ্যাপ্লিকেশন পারফরমেন্স মনিটরিং (APM) টুল ব্যবহার করবেন। আপনি যদি একটি খুব বড় কোম্পানি হন, আপনি নিজেই এটি তৈরি করতে পারেন। ছোট পোশাকের জন্য, যদিও, একটি APM বাছাই করা অফ-দ্য-শেল্ফ। আপনাকে একটি মাসিক সাবস্ক্রিপশন দিতে হবে, তবে তারা যে তথ্য প্রদান করে তা এর জন্য বেশি করে।
মেমরি লিক শনাক্ত করার জন্য, আপনি সার্ভার খুঁজে পেতে চান বা সময়ের সাথে সাথে মেমরি ব্যবহার (কখনও কখনও আরএসএস বলা হয়) গ্রাফগুলি প্রক্রিয়া করতে চান৷ মোতায়েন হওয়ার কিছুক্ষণ পরেই একটি স্বাস্থ্যকর অ্যাপের অ্যাপসিগন্যালের 'প্রসেস মেমরি ব্যবহার' ড্যাশবোর্ড থেকে একটি উদাহরণ স্ক্রিনশট:

এবং এখানে স্থাপনের পরে একটি অস্বাস্থ্যকর অ্যাপ রয়েছে:

AppSignal এমনকি জিসি এবং হিপ স্লটের মতো রুবি ভিএম পরিসংখ্যানও দেখাবে, যা আপনাকে মেমরি লিকের জন্য আরও পরিষ্কার সংকেত দিতে পারে। যদি লাইভ স্লটস্কিপের সংখ্যা বাড়তে থাকে, তাহলে আপনার একটি লিক আছে!

রুবির জন্য AppSignal সম্পর্কে আরও পড়ুন।
র্যাপ আপ এবং আরও পড়া
এই পোস্টে, আমরা রুবির স্মৃতি ব্যবস্থাপনা এবং আবর্জনা সংগ্রহকারীর একটি দ্রুত সফর নিয়েছি। তারপর আমরা নির্ণয় করেছি কিভাবে ইউনিক্স টুলস এবং রুবির জিসি মডিউল ব্যবহার করে মেমরি লিক আবিষ্কার করা যায়।
পরের বার, আমরা দেখব কিভাবে memory_profiler ব্যবহার করতে হয় এবং derailed_benchmarks লিক খুঁজে বের করতে এবং ঠিক করতে।
ইতিমধ্যে, আপনি আমরা যে সরঞ্জামগুলি ব্যবহার করেছি সে সম্পর্কে আরও পড়তে পারেন:
watchpspgrep
অতিরিক্ত আরও পড়া:
GCমডিউল ডকুমেন্টেশনObjectSpaceমডিউল ডকুমেন্টেশন- গর্বেজ কালেকশন ডিপ ডাইভ
- পরিবর্তনশীল প্রস্থ বরাদ্দ
শুভ কোডিং, এবং পরের বার দেখা হবে!
পি.এস. আপনি যদি রুবি ম্যাজিক পোস্টগুলি প্রেস থেকে বের হওয়ার সাথে সাথে পড়তে চান তবে আমাদের রুবি ম্যাজিক নিউজলেটারে সাবস্ক্রাইব করুন এবং একটি পোস্ট মিস করবেন না!