সংক্ষিপ্ত সংস্করণ: সর্বদা calloc()
পরিবর্তে ব্যবহার করুন malloc()+memset()
। বেশিরভাগ ক্ষেত্রে, তারা একই হবে। কিছু ক্ষেত্রে calloc()
কম কাজ করবে কারণ এটি memset()
পুরোপুরি এড়িয়ে যেতে পারে। অন্য ক্ষেত্রে, calloc()
এমনকি প্রতারণা করতে পারে এবং কোনও মেমোরি বরাদ্দও করতে পারে না! যাইহোক, malloc()+memset()
সর্বদা কাজের সম্পূর্ণ পরিমাণে কাজ করবে।
এটি বোঝার জন্য মেমরি সিস্টেমের একটি স্বল্প ভ্রমণ প্রয়োজন tour
স্মৃতির দ্রুত সফর Quick
এখানে চারটি প্রধান অংশ রয়েছে: আপনার প্রোগ্রাম, স্ট্যান্ডার্ড লাইব্রেরি, কার্নেল এবং পৃষ্ঠা সারণী। আপনি ইতিমধ্যে আপনার প্রোগ্রাম জানেন, তাই ...
মত স্মৃতি allocators malloc()
এবং calloc()
বেশিরভাগ আছে মেমরি বড় পুল মধ্যে এবং তাদের গ্রুপ (কিলোবাইট 100 টিরও 1 বাইট থেকে কিছু) ছোট বরাদ্দ নিতে। উদাহরণস্বরূপ, আপনি যদি 16 বাইট বরাদ্দ করেন তবে malloc()
প্রথমে এর একটি পুলের মধ্যে 16 বাইট পাওয়ার চেষ্টা করবেন এবং পুলটি শুকিয়ে গেলে কার্নেল থেকে আরও মেমরি চাইবেন। যাইহোক, যে প্রোগ্রামটির বিষয়ে আপনি জিজ্ঞাসা করছেন তা একবারে প্রচুর পরিমাণে মেমরির জন্য বরাদ্দ করা হচ্ছে, malloc()
এবং calloc()
কেবল কার্নেল থেকে সরাসরি সেই মেমরিটির জন্য জিজ্ঞাসা করবে। এই আচরণের প্রান্তিকতা আপনার সিস্টেমে নির্ভর করে তবে আমি থ্রোসোল্ড হিসাবে ব্যবহৃত 1 এমআইবি দেখেছি।
কার্নেল প্রতিটি প্রক্রিয়াতে প্রকৃত র্যাম বরাদ্দ করার জন্য এবং প্রক্রিয়াগুলি অন্যান্য প্রক্রিয়াগুলির স্মৃতিতে হস্তক্ষেপ না করে তা নিশ্চিত করার জন্য দায়বদ্ধ। একে মেমোরি প্রোটেকশন বলা হয় , এটি 1990 এর দশক থেকে ময়লা সাধারণ এবং এটিই কারণ যে কোনও একটি প্রোগ্রাম পুরো সিস্টেমটি না নামিয়ে ক্রাশ করতে পারে। সুতরাং যখন কোনও প্রোগ্রামের আরও মেমরির প্রয়োজন হয় তবে এটি কেবল মেমরিটি নিতে পারে না, পরিবর্তে এটি সিস্টেম কলের মতো mmap()
বা ব্যবহার করে কার্নেল থেকে মেমরির জন্য জিজ্ঞাসা করে sbrk()
। কার্নেল পৃষ্ঠার সারণিটি সংশোধন করে প্রতিটি প্রক্রিয়াতে র্যাম দেবে।
পৃষ্ঠা টেবিলটি মেমরির ঠিকানাগুলি প্রকৃত শারীরিক র্যামে ম্যাপ করে। আপনার প্রসেসের ঠিকানাগুলি, 32x-বিট সিস্টেমে 0x00000000 থেকে 0xFFFFFFFFF, সত্যিকারের মেমরি নয় তবে পরিবর্তে ভার্চুয়াল মেমরির ঠিকানা। প্রসেসর এই ঠিকানাগুলি 4 কিবি পৃষ্ঠায় বিভক্ত করে এবং প্রতিটি পৃষ্ঠা পৃষ্ঠা সারণীটি পরিবর্তন করে বিভিন্ন শারীরিক র্যামের জন্য পৃথক করা যেতে পারে। পৃষ্ঠার সারণিটি সংশোধন করার জন্য কেবল কার্নেলকেই অনুমতি দেওয়া হয়েছে।
কিভাবে এটি কাজ করে না
256 এমআইবি বরাদ্দকরণ কীভাবে কাজ করে না তা এখানে :
আপনার প্রক্রিয়া কল calloc()
করে 256 এমআইবি চেয়েছে।
মানক গ্রন্থাগারটি mmap()
256 মাইবি কল করে asks
কার্নেলটি 256 এমআইবি অব্যবহৃত র্যামের সন্ধান করে এবং পৃষ্ঠা সারণীতে পরিবর্তন করে এটি আপনার প্রক্রিয়াতে দেয়।
স্ট্যান্ডার্ড লাইব্রেরিটি র্যামটি শূন্য করে memset()
এবং সেখান থেকে ফিরে আসে calloc()
।
আপনার প্রক্রিয়াটি শেষ পর্যন্ত প্রস্থান করে এবং কার্নেলটি র্যামটিকে পুনরায় দাবি করে যাতে এটি অন্য কোনও প্রক্রিয়া দ্বারা ব্যবহার করা যায়।
এটি আসলে কীভাবে কাজ করে
উপরের প্রক্রিয়াটি কার্যকর হবে তবে এটি কেবল এইভাবে ঘটে না। তিনটি প্রধান পার্থক্য আছে।
যখন আপনার প্রক্রিয়া কার্নেল থেকে নতুন মেমরি পায়, সেই স্মৃতি সম্ভবত অন্য কোনও প্রক্রিয়া দ্বারা ব্যবহৃত হয়েছিল। এটি একটি সুরক্ষা ঝুঁকি। যদি সেই স্মৃতিটিতে পাসওয়ার্ড, এনক্রিপশন কী বা গোপন সালসা রেসিপি থাকে? সংবেদনশীল ডেটা ফাঁস হওয়া থেকে বাঁচাতে, কার্নেল সর্বদা কোনও প্রক্রিয়া দেওয়ার আগে মেমরিটিকে স্ক্রাব করে। আমরা স্মৃতিটিকে শূন্য করে স্ক্রাব করতে পারি এবং নতুন স্মৃতি যদি শূন্য হয় তবে আমরা এটির গ্যারান্টিও বানাতে পারি, তাই mmap()
গ্যারান্টি দেয় যে এটির নতুন স্মৃতি ফিরে আসে সর্বদা শূন্য।
সেখানে প্রচুর প্রোগ্রাম রয়েছে যা মেমরি বরাদ্দ করে তবে এখনই মেমরিটি ব্যবহার করে না। কিছু সময় মেমরি বরাদ্দ করা হয় তবে কখনও ব্যবহৃত হয় না। কার্নেল এটি জানে এবং অলস। আপনি যখন নতুন মেমরি বরাদ্দ করেন, কার্নেল পৃষ্ঠার টেবিলটি একেবারেই স্পর্শ করে না এবং আপনার প্রক্রিয়াতে কোনও র্যাম দেয় না। পরিবর্তে, এটি আপনার প্রক্রিয়াতে কিছু ঠিকানার জায়গা খুঁজে বের করে, সেখানে যাওয়ার কথাটি একটি নোট তৈরি করে এবং একটি প্রতিশ্রুতি দেয় যে এটি যদি আপনার প্রোগ্রামটি আসলে ব্যবহার করে তবে সেখানে র্যাম রাখবে। যখন আপনার প্রোগ্রামটি সেই ঠিকানাগুলি থেকে পড়তে বা লিখতে চেষ্টা করে, প্রসেসর একটি পৃষ্ঠা ত্রুটি এবং সেই ঠিকানাগুলিতে র্যাম নির্ধারণের কার্নেল পদক্ষেপগুলি ট্রিগার করে এবং আপনার প্রোগ্রামটি পুনরায় চালু করে। আপনি যদি কখনও স্মৃতি ব্যবহার না করেন তবে পৃষ্ঠার ত্রুটি কখনই ঘটে না এবং আপনার প্রোগ্রামটি কখনই র্যাম পায় না।
কিছু প্রক্রিয়া মেমরি বরাদ্দ করে এবং তারপরে এটিকে পরিবর্তন না করেই পড়ে। এর অর্থ হ'ল বিভিন্ন প্রক্রিয়া জুড়ে মেমরির প্রচুর পৃষ্ঠাগুলি ফিরে আসা আদি শূন্যগুলিতে পূর্ণ হতে পারে mmap()
। যেহেতু এই পৃষ্ঠাগুলি সমস্ত একই, কার্নেলটি এই সমস্ত ভার্চুয়াল ঠিকানাগুলিকে জিরো দিয়ে ভরা মেমরির একক ভাগ করা 4 কিবি পৃষ্ঠায় নির্দেশ করে। আপনি যদি সেই মেমোরিতে লেখার চেষ্টা করেন, প্রসেসর অন্য পৃষ্ঠার ত্রুটি ট্রিগার করে এবং কার্নেলটি আপনাকে অন্য একটি প্রোগ্রামের সাথে ভাগ করে না দেওয়া শূন্যগুলির একটি নতুন পৃষ্ঠা দেওয়ার জন্য পদক্ষেপ নিচ্ছে।
চূড়ান্ত প্রক্রিয়াটি আরও দেখতে লাগে:
আপনার প্রক্রিয়া কল calloc()
করে 256 এমআইবি চেয়েছে।
মানক গ্রন্থাগারটি mmap()
256 মাইবি কল করে asks
কার্নেলটি 256 এমআইবি অব্যবহৃত অ্যাড্রেস স্পেসের সন্ধান করে, সেই ঠিকানা স্থানটি এখন কীসের জন্য ব্যবহৃত হয় এবং ফিরে আসে সে সম্পর্কে একটি নোট তৈরি করে।
মান গ্রন্থাগার জানে যে ফল mmap()
সবসময় শূণ্যসমূহ দিয়ে পূর্ণ (অথবা হতে হবে একবার এটা আসলে কিছু র্যাম পায়), তাই এটি মেমরি স্পর্শ করে না, তাই কোন পেজ ফল্ট, এবং র্যাম আপনার প্রক্রিয়া কখনো দেওয়া হয় ।
আপনার প্রক্রিয়াটি অবশেষে প্রস্থান করে, এবং কার্নেলটি র্যাম পুনরায় দাবি করার প্রয়োজন হয় না কারণ এটি কখনই প্রথম স্থানে বরাদ্দ ছিল না।
আপনি যদি memset()
পৃষ্ঠাটি শূন্য করতে ব্যবহার করেন memset()
তবে পৃষ্ঠার ত্রুটিটি ট্রিগার করবে, র্যাম বরাদ্দ পেতে দেবে এবং এরপরে এটি শূন্যে ভরা থাকলেও এটি শূন্য করবে। এটি অতিরিক্ত কাজের একটি বিশাল পরিমাণ, এবং কেন এবং এর calloc()
চেয়ে দ্রুত কেন তা ব্যাখ্যা করে । যাইহোক মেমরি ব্যবহার করে যদি শেষ হয় তবে তার চেয়ে এখনও দ্রুত এবং পার্থক্যটি এতটা হাস্যকর নয়।malloc()
memset()
calloc()
malloc()
memset()
এটি সবসময় কাজ করে না
সমস্ত সিস্টেমে পেজড ভার্চুয়াল মেমরি নেই, সুতরাং সমস্ত সিস্টেম এই অপ্টিমাইজেশন ব্যবহার করতে পারে না। এটি 80286 এর মতো পুরানো প্রসেসরের পাশাপাশি এম্বেড হওয়া প্রসেসরের ক্ষেত্রেও প্রযোজ্য যা একটি পরিশীলিত মেমরি পরিচালনা ইউনিটের জন্য খুব ছোট।
এটি সর্বদা ছোট বরাদ্দ দিয়ে কাজ করবে না। আরও ছোট বরাদ্দের সাথে, calloc()
সরাসরি কার্নেলে যাওয়ার পরিবর্তে ভাগ করা পুল থেকে স্মৃতি পেয়ে যায়। সাধারণভাবে, ভাগ করা পুলটিতে পুরানো মেমরি যা এতে ব্যবহার করা হয়েছিল এবং মুক্ত হয়েছিল তা থেকে এটিতে থাকা জঙ্ক ডেটা থাকতে পারে free()
, তাই calloc()
সেই স্মৃতিটি গ্রহণ করতে এবং memset()
এটি পরিষ্কার করার জন্য কল করতে পারে। সাধারণ বাস্তবায়নগুলি ভাগ করা পুলের কোন অংশগুলি প্রাচীন এবং এখনও জিরো দিয়ে পূর্ণ তা ট্র্যাক করবে তবে সমস্ত বাস্তবায়ন এটি করে না।
কিছু ভুল উত্তর নিষ্পত্তি করা হচ্ছে
অপারেটিং সিস্টেমের উপর নির্ভর করে, কার্নেলটি ফ্রি সময়ে মেমরি শূন্য করতে পারে বা নাও পারে, যদি আপনার পরে কিছু শূন্য স্মৃতি পাওয়ার প্রয়োজন হয়। লিনাক্স সময়ের আগে স্মৃতি শূন্য হয় না এবং ড্রাগনফ্লাই বিএসডি সম্প্রতি তাদের কার্নেল থেকে এই বৈশিষ্ট্যটি সরিয়ে ফেলেছে । অন্য কিছু কার্নেল সময় পূর্বে শূন্য মেমরি করে। জিরোয়েজ পৃষ্ঠাগুলি নিষ্ক্রিয় নিষ্ক্রিয়তা যাইহোক বড় পারফরম্যান্স পার্থক্য ব্যাখ্যা করতে যথেষ্ট নয়।
calloc()
ফাংশনের কিছু বিশেষ মেমরি প্রান্তিককৃত সংস্করণ ব্যবহার করছে না memset()
, এবং যে এটি অনেক দ্রুত যাহাই হউক না কেন করতে হবে না। memset()
আধুনিক প্রসেসরের জন্য বেশিরভাগ বাস্তবায়নগুলি এ জাতীয় চেহারা:
function memset(dest, c, len)
// one byte at a time, until the dest is aligned...
while (len > 0 && ((unsigned int)dest & 15))
*dest++ = c
len -= 1
// now write big chunks at a time (processor-specific)...
// block size might not be 16, it's just pseudocode
while (len >= 16)
// some optimized vector code goes here
// glibc uses SSE2 when available
dest += 16
len -= 16
// the end is not aligned, so one byte at a time
while (len > 0)
*dest++ = c
len -= 1
সুতরাং আপনি দেখতে পাচ্ছেন memset()
যে খুব দ্রুত এবং আপনি মেমরির বৃহত ব্লকের জন্য আরও ভাল কিছু পেতে যাচ্ছেন না।
সত্য যে memset()
মেমরি zeroing যে ইতিমধ্যে zeroed হয় মানে মেমরির দুইবার zeroed পরার, কিন্তু যে শুধুমাত্র একটি 2x কর্মক্ষমতা পার্থক্য ব্যাখ্যা করে। এখানে পারফরম্যান্সের পার্থক্যটি অনেক বড় (আমি malloc()+memset()
এবং আমার সিস্টেমের মধ্যে আমি তিনটিরও বেশি আকারের পরিমাপ করেছি calloc()
)।
পার্টি কৌশল
10 বার লুপিংয়ের পরিবর্তে, এমন একটি প্রোগ্রাম লিখুন যা মেমরির বরাদ্দ করে malloc()
বা calloc()
NULL প্রদান করে।
যোগ করলে কী হয় memset()
?