কন্টিগুয়াস মেমরি অ্যালোকেশন
এই পাঠে যা শিখবেন
- ফিক্সড বনাম ভ্যারিয়েবল পার্টিশনিং এবং প্রতিটির নিজস্ব ফ্র্যাগমেন্টেশন সমস্যা
- ইন্টারনাল ফ্র্যাগমেন্টেশন বনাম এক্সটার্নাল ফ্র্যাগমেন্টেশনের নির্ভুল পার্থক্য
- first-fit, best-fit, worst-fit — তিনটি অ্যালোকেশন স্ট্র্যাটেজি এবং কখন কোনটি ভালো/খারাপ পারফর্ম করে
- Python দিয়ে তিনটি স্ট্র্যাটেজিরই বাস্তব বাস্তবায়ন — একই অনুরোধ সিকোয়েন্সে সরাসরি তুলনা
১ · প্রতিটি প্রসেসকে একটি একটানা ব্লক
সবচেয়ে সরল মেমরি অ্যালোকেশন পদ্ধতি — প্রতিটি প্রসেসকে ফিজিক্যাল মেমরির একটি সম্পূর্ণ কন্টিগুয়াস (একটানা) ব্লকContiguous Allocationএকটি প্রসেসকে ফিজিক্যাল মেমরির শুরু থেকে শেষ পর্যন্ত একটানা একটি ব্লক হিসেবে বরাদ্দ দেওয়া — কোনো ফাঁকে ফাঁকে ভাগ করা নয়। দেওয়া — L27-এর base/limit register দিয়ে এই ব্লকের শুরু ও আকার ট্র্যাক করা হয়। কিন্তু মেমরিকে কীভাবে এই ব্লকগুলোতে ভাগ করা হবে, তার দুটি ভিন্ন কৌশল আছে।
মেমরিকে আগে থেকেই নির্দিষ্ট সংখ্যক নির্দিষ্ট-আকারের চাংকে ভাগ করা হয়। সরল, কিন্তু একটি প্রসেস তার পার্টিশনের চেয়ে ছোট হলে অবশিষ্ট জায়গা নষ্ট হয় — ইন্টারনাল ফ্র্যাগমেন্টেশন।
প্রতিটি প্রসেসের জন্য ঠিক তার আকারের সমান পার্টিশন তৈরি হয় — ইন্টারনাল ফ্র্যাগমেন্টেশন এড়ানো যায়। কিন্তু প্রসেস আসা-যাওয়ার ফলে ছোট ছোট বিক্ষিপ্ত ফাঁকা "হোল" তৈরি হয় — এক্সটার্নাল ফ্র্যাগমেন্টেশন।
ইন্টারনাল: বরাদ্দকৃত ব্লকের ভেতরেই অব্যবহৃত জায়গা নষ্ট হয় (প্রসেস তার পুরো পার্টিশন ব্যবহার করে না)। এক্সটার্নাল: মোট ফাঁকা মেমরি হয়তো যথেষ্ট, কিন্তু কোনো একটি একক হোল যথেষ্ট বড় নয় — ফাঁকা জায়গা ব্লকগুলোর মাঝে মাঝে বিক্ষিপ্তভাবে ছড়িয়ে থাকে বলে। এই দ্বিতীয় সমস্যাটিই — এক্সটার্নাল ফ্র্যাগমেন্টেশন — এত গুরুতর যে এটি সমাধান করতেই L29-এ পেজিং আবিষ্কৃত হয়েছিল।
২ · কোন হোলটি বেছে নেওয়া হবে — তিনটি স্ট্র্যাটেজি
ভ্যারিয়েবল পার্টিশনিং-এ যখন একটি নতুন প্রসেসের অনুরোধ আসে, ফাঁকা "হোল"গুলোর তালিকা থেকে কোনটি ব্যবহার করা হবে তা ঠিক করতে হয়। তিনটি ক্লাসিক স্ট্র্যাটেজি —
তালিকার প্রথম যে হোলটি যথেষ্ট বড়, সেটিই ব্যবহার করো। খোঁজা দ্রুত, কিন্তু হোল বাছাইয়ে কোনো অপ্টিমাইজেশন নেই।
যথেষ্ট বড় হোলগুলোর মধ্যে সবচেয়ে ছোটটি বেছে নাও — প্রতি অ্যালোকেশনে অপচয় কম হয়, কিন্তু বহু ছোট, প্রায়-অকেজো হোল রেখে যেতে পারে।
ইচ্ছাকৃতভাবে সবচেয়ে বড় হোলটি বেছে নাও — যুক্তি হলো, বড় একটি অবশিষ্টাংশ পরে বেশি কাজে লাগতে পারে। বাস্তবে সবচেয়ে কম ব্যবহৃত হয়।
৩ · তিনটি স্ট্র্যাটেজির বাস্তব বাস্তবায়ন
নিচের কোড সেলে একই ৫টি ফাঁকা হোল এবং একই ৪টি অনুরোধের সিকোয়েন্সের বিপরীতে তিনটি স্ট্র্যাটেজিই চালানো হয়েছে — প্রতিটি ধাপে কোন হোলটি বেছে নেওয়া হলো তা প্রিন্ট হবে, এবং শেষে অবশিষ্ট ছোট (< 90 ইউনিট, কার্যত অকেজো) হোলের সংখ্যা গণনা করা হয়েছে।
# first-fit, best-fit, worst-fit -- একই হোল তালিকা ও একই অনুরোধের বিপরীতে
def first_fit(holes, size):
for i, (start, hole_size) in enumerate(holes):
if hole_size >= size:
return i
return None
def best_fit(holes, size):
best_i, best_size = None, None
for i, (start, hole_size) in enumerate(holes):
if hole_size >= size and (best_size is None or hole_size < best_size):
best_i, best_size = i, hole_size
return best_i
def worst_fit(holes, size):
worst_i, worst_size = None, None
for i, (start, hole_size) in enumerate(holes):
if hole_size >= size and (worst_size is None or hole_size > worst_size):
worst_i, worst_size = i, hole_size
return worst_i
def run_strategy(strategy_fn, name):
holes = [(0, 100), (100, 500), (600, 200), (800, 300), (1100, 600)]
requests = [212, 417, 112, 426]
print(f"--- {name} ---")
for req in requests:
idx = strategy_fn(holes, req)
if idx is None:
print(f"অনুরোধ {req}: কোনো হোল যথেষ্ট বড় নয় -> ব্যর্থ")
continue
start, hole_size = holes[idx]
print(f"অনুরোধ {req}: হোল নির্বাচিত -> start={start}, size={hole_size}")
leftover = hole_size - req
if leftover > 0:
holes[idx] = (start + req, leftover)
else:
holes.pop(idx)
tiny_holes = [h for h in holes if h[1] < 90]
print("অবশিষ্ট হোলসমূহ:", holes)
print(f"ছোট/অকেজো হোল (< 90 ইউনিট): {len(tiny_holes)}\n")
run_strategy(first_fit, "First-Fit")
run_strategy(best_fit, "Best-Fit")
run_strategy(worst_fit, "Worst-Fit")
কোনো একক স্ট্র্যাটেজিই সব পরিস্থিতিতে সেরা নয় — first-fit দ্রুত, best-fit প্রতি-অ্যালোকেশন অপচয় কমায় কিন্তু দীর্ঘমেয়াদে ছোট হোলের স্তূপ তৈরি করে, worst-fit ব্যবহারিকভাবে কম কার্যকর। কিন্তু আসল সমস্যাটি — এক্সটার্নাল ফ্র্যাগমেন্টেশন — তিনটি স্ট্র্যাটেজিতেই থেকে যায়, কারণ মূল সমস্যাটি হলো ভ্যারিয়েবল-সাইজ কন্টিগুয়াস ব্লক ব্যবহার করা। L29-এ আমরা দেখব কীভাবে ফিক্সড-সাইজ পেজ ব্যবহার করে এই সমস্যাটিই সম্পূর্ণরূপে দূর করা যায়।
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।
প্র ০১ ফিক্সড পার্টিশনিং সমাধান করলে ইন্টারনাল ফ্র্যাগমেন্টেশন এড়ানো যায় কেন সমস্যা রয়েই যায়?
ভ্যারিয়েবল পার্টিশনিং প্রতিটি প্রসেসকে ঠিক তার প্রয়োজনীয় আকারের ব্লক দেয় বলে ইন্টারনাল ফ্র্যাগমেন্টেশন (ব্লকের ভেতরের অপচয়) নেই ঠিকই। কিন্তু প্রসেস লোড ও টার্মিনেট হতে থাকলে মেমরিতে বিভিন্ন আকারের ফাঁকা "হোল" বিক্ষিপ্তভাবে তৈরি হয় — এবং কোনো নতুন প্রসেস এই ছোট ছোট হোলের একটিতেও না ধরলে, মোট ফাঁকা জায়গা যথেষ্ট থাকলেও প্রসেসটি বসানো যায় না। এটিই এক্সটার্নাল ফ্র্যাগমেন্টেশন — একটি ভিন্ন, কিন্তু সমান গুরুতর সমস্যা।
প্র ০২ Best-fit "সবচেয়ে কম অপচয় করে" তবু কেন এটি দীর্ঘমেয়াদে বেশি ছোট, অকেজো হোল তৈরি করতে পারে?
Best-fit প্রতিটি অনুরোধের জন্য যথাসম্ভব নিখুঁতভাবে-ফিট হওয়া হোল বেছে নেয় — যার মানে প্রায়ই খুব সামান্য অবশিষ্টাংশ থেকে যায় (যেমন একটি 300-আকারের হোল থেকে 212 নেওয়ার পর মাত্র 88 বাকি থাকে)। এই ধরনের ছোট অবশিষ্টাংশ ভবিষ্যতের কোনো বাস্তবসম্মত অনুরোধের জন্য প্রায়ই যথেষ্ট বড় হয় না — ফলে সময়ের সাথে সাথে এরকম বহু ছোট, কার্যত অব্যবহারযোগ্য টুকরো জমা হতে থাকে, যেমনটা উপরের কোড সেলে Best-Fit-এর ফলাফলে দেখা গেছে।
প্র ০৩ উপরের কোড সেলে শেষ অনুরোধ (426) First-Fit ও Worst-Fit-এ ব্যর্থ হলো কেন, অথচ Best-Fit-এ সফল হলো?
First-Fit ও Worst-Fit উভয়েই আগের ধাপগুলোতে বড় হোলগুলো (বিশেষত 500 ও 600-আকারেরগুলো) আক্রমণাত্মকভাবে ব্যবহার করে ফেলে, শেষে ছোট ছোট টুকরো রেখে যায় যার কোনোটিই 426-এর জন্য যথেষ্ট বড় নয়। Best-Fit যেহেতু প্রতিটি অনুরোধে সবচেয়ে ছোট-কিন্তু-যথেষ্ট হোল বেছে নেয়, তাই 500-আকারের হোলটি প্রথম দুই অনুরোধে স্পর্শ না করে বাকি থেকে যায় — এবং শেষ পর্যন্ত সেটিই 426-এর জন্য কাজে আসে। এটি দেখায় কীভাবে "স্থানীয়ভাবে সেরা" সিদ্ধান্ত সবসময় "দীর্ঘমেয়াদে সেরা" ফলাফল দেয় না, বরং পরিস্থিতিভেদে ভিন্ন।
অনুশীলন
-
চিন্তা করুন: যদি একটি নতুন প্রসেসের আকার হোল-তালিকার যেকোনো একক হোলের চেয়ে বড় হয়, কিন্তু সবগুলো হোলের সমষ্টির চেয়ে ছোট হয় — তাহলে কী হবে, এবং কেন?
তিনটি স্ট্র্যাটেজিই ব্যর্থ হবে — কারণ প্রতিটি স্ট্র্যাটেজি একটি একক কন্টিগুয়াস হোল খোঁজে, একাধিক হোল একসাথে ব্যবহার করার কোনো উপায় নেই (কন্টিগুয়াস অ্যালোকেশনের সংজ্ঞা অনুযায়ী প্রসেসটি একটানা মেমরিতেই বসতে হবে)। এটিই এক্সটার্নাল ফ্র্যাগমেন্টেশনের সবচেয়ে স্পষ্ট উদাহরণ — মোট ফাঁকা জায়গা যথেষ্ট, তবু কোনো একক টুকরো যথেষ্ট বড় নয় বলে বরাদ্দ সম্ভব নয়।
-
পরীক্ষা করুন: উপরের কোড সেলে
requestsতালিকার শেষে আরেকটি অনুরোধ50যোগ করে Run চাপুন — তিনটি স্ট্র্যাটেজিতেই এটি সফল হয় কি না দেখুন।50-এর মতো ছোট অনুরোধ প্রায় সব ক্ষেত্রেই সফল হবে, কারণ আগের ধাপগুলোর অবশিষ্টাংশ থেকেই প্রায় সবসময় অন্তত একটি হোল 50 ইউনিটের চেয়ে বড় থেকে যায় (Best-Fit-এর ক্ষেত্রে হয়তো এটিই সবচেয়ে ছোট এমন একটি টুকরোতে বসবে)। এটি প্রমাণ করে ছোট প্রসেস বরাদ্দ পাওয়া তুলনামূলক সহজ — সমস্যাটি মূলত বড়, ভালো-আকারের প্রসেসের জন্য একটানা জায়গা খুঁজে পাওয়ায়।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- পরবর্তী পাঠ পড়ুন L29 পেজিং — কীভাবে ফিক্সড-সাইজ পেজ ব্যবহার করে এই পাঠের এক্সটার্নাল ফ্র্যাগমেন্টেশন সমস্যা সম্পূর্ণরূপে দূর করা হয়।
- আগের পাঠ ফিরে দেখুন L27 base/limit register-ভিত্তিক MMU সিমুলেশন — এই পাঠের প্রতিটি হোল-অ্যালোকেশন আসলে এই সরল সূত্রেরই বাস্তব প্রয়োগ।
- কোর্সের সম্পূর্ণ সিলেবাস দেখুন ৫৬টি পাঠ সব ৫৬টি পাঠের তালিকা এবং মডিউলভিত্তিক অগ্রগতি দেখুন।