কেন ম্যালোক + মেমসেট কলোকের চেয়ে ধীর?


256

এটি পরিচিত যা এটি বরাদ্দ করা স্মৃতিটিকে আরম্ভ করার callocচেয়ে আলাদা malloc। সাথে calloc, স্মৃতিটি শূন্যে সেট করা আছে। সঙ্গে malloc, স্মৃতি পরিষ্কার হয় না।

তাই দৈনন্দিন কাজের ক্ষেত্রে, আমি + callocহিসাবে বিবেচনা করি । ঘটনাচক্রে, মজা করার জন্য, আমি একটি বেঞ্চমার্কের জন্য নিম্নলিখিত কোডটি লিখেছিলাম।mallocmemset

ফলাফল বিভ্রান্তিকর।

কোড 1:

#include<stdio.h>
#include<stdlib.h>
#define BLOCK_SIZE 1024*1024*256
int main()
{
        int i=0;
        char *buf[10];
        while(i<10)
        {
                buf[i] = (char*)calloc(1,BLOCK_SIZE);
                i++;
        }
}

কোড 1 আউটপুট:

time ./a.out  
**real 0m0.287s**  
user 0m0.095s  
sys 0m0.192s  

কোড 2:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define BLOCK_SIZE 1024*1024*256
int main()
{
        int i=0;
        char *buf[10];
        while(i<10)
        {
                buf[i] = (char*)malloc(BLOCK_SIZE);
                memset(buf[i],'\0',BLOCK_SIZE);
                i++;
        }
}

কোড 2 আউটপুট:

time ./a.out   
**real 0m2.693s**  
user 0m0.973s  
sys 0m1.721s  

কোড 2 এর memsetসাথে প্রতিস্থাপন bzero(buf[i],BLOCK_SIZE)করলে একই ফলাফল পাওয়া যায়।

আমার প্রশ্ন হ'ল কেন malloc+ memsetএত বেশি ধীর calloc? কীভাবে তা করতে callocপারে?

উত্তর:


455

সংক্ষিপ্ত সংস্করণ: সর্বদা 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 এমআইবি বরাদ্দকরণ কীভাবে কাজ করে না তা এখানে :

  1. আপনার প্রক্রিয়া কল calloc()করে 256 এমআইবি চেয়েছে।

  2. মানক গ্রন্থাগারটি mmap()256 মাইবি কল করে asks

  3. কার্নেলটি 256 এমআইবি অব্যবহৃত র‌্যামের সন্ধান করে এবং পৃষ্ঠা সারণীতে পরিবর্তন করে এটি আপনার প্রক্রিয়াতে দেয়।

  4. স্ট্যান্ডার্ড লাইব্রেরিটি র‌্যামটি শূন্য করে memset()এবং সেখান থেকে ফিরে আসে calloc()

  5. আপনার প্রক্রিয়াটি শেষ পর্যন্ত প্রস্থান করে এবং কার্নেলটি র‌্যামটিকে পুনরায় দাবি করে যাতে এটি অন্য কোনও প্রক্রিয়া দ্বারা ব্যবহার করা যায়।

এটি আসলে কীভাবে কাজ করে

উপরের প্রক্রিয়াটি কার্যকর হবে তবে এটি কেবল এইভাবে ঘটে না। তিনটি প্রধান পার্থক্য আছে।

  • যখন আপনার প্রক্রিয়া কার্নেল থেকে নতুন মেমরি পায়, সেই স্মৃতি সম্ভবত অন্য কোনও প্রক্রিয়া দ্বারা ব্যবহৃত হয়েছিল। এটি একটি সুরক্ষা ঝুঁকি। যদি সেই স্মৃতিটিতে পাসওয়ার্ড, এনক্রিপশন কী বা গোপন সালসা রেসিপি থাকে? সংবেদনশীল ডেটা ফাঁস হওয়া থেকে বাঁচাতে, কার্নেল সর্বদা কোনও প্রক্রিয়া দেওয়ার আগে মেমরিটিকে স্ক্রাব করে। আমরা স্মৃতিটিকে শূন্য করে স্ক্রাব করতে পারি এবং নতুন স্মৃতি যদি শূন্য হয় তবে আমরা এটির গ্যারান্টিও বানাতে পারি, তাই mmap()গ্যারান্টি দেয় যে এটির নতুন স্মৃতি ফিরে আসে সর্বদা শূন্য।

  • সেখানে প্রচুর প্রোগ্রাম রয়েছে যা মেমরি বরাদ্দ করে তবে এখনই মেমরিটি ব্যবহার করে না। কিছু সময় মেমরি বরাদ্দ করা হয় তবে কখনও ব্যবহৃত হয় না। কার্নেল এটি জানে এবং অলস। আপনি যখন নতুন মেমরি বরাদ্দ করেন, কার্নেল পৃষ্ঠার টেবিলটি একেবারেই স্পর্শ করে না এবং আপনার প্রক্রিয়াতে কোনও র‌্যাম দেয় না। পরিবর্তে, এটি আপনার প্রক্রিয়াতে কিছু ঠিকানার জায়গা খুঁজে বের করে, সেখানে যাওয়ার কথাটি একটি নোট তৈরি করে এবং একটি প্রতিশ্রুতি দেয় যে এটি যদি আপনার প্রোগ্রামটি আসলে ব্যবহার করে তবে সেখানে র‌্যাম রাখবে। যখন আপনার প্রোগ্রামটি সেই ঠিকানাগুলি থেকে পড়তে বা লিখতে চেষ্টা করে, প্রসেসর একটি পৃষ্ঠা ত্রুটি এবং সেই ঠিকানাগুলিতে র‌্যাম নির্ধারণের কার্নেল পদক্ষেপগুলি ট্রিগার করে এবং আপনার প্রোগ্রামটি পুনরায় চালু করে। আপনি যদি কখনও স্মৃতি ব্যবহার না করেন তবে পৃষ্ঠার ত্রুটি কখনই ঘটে না এবং আপনার প্রোগ্রামটি কখনই র‍্যাম পায় না।

  • কিছু প্রক্রিয়া মেমরি বরাদ্দ করে এবং তারপরে এটিকে পরিবর্তন না করেই পড়ে। এর অর্থ হ'ল বিভিন্ন প্রক্রিয়া জুড়ে মেমরির প্রচুর পৃষ্ঠাগুলি ফিরে আসা আদি শূন্যগুলিতে পূর্ণ হতে পারে mmap()। যেহেতু এই পৃষ্ঠাগুলি সমস্ত একই, কার্নেলটি এই সমস্ত ভার্চুয়াল ঠিকানাগুলিকে জিরো দিয়ে ভরা মেমরির একক ভাগ করা 4 কিবি পৃষ্ঠায় নির্দেশ করে। আপনি যদি সেই মেমোরিতে লেখার চেষ্টা করেন, প্রসেসর অন্য পৃষ্ঠার ত্রুটি ট্রিগার করে এবং কার্নেলটি আপনাকে অন্য একটি প্রোগ্রামের সাথে ভাগ করে না দেওয়া শূন্যগুলির একটি নতুন পৃষ্ঠা দেওয়ার জন্য পদক্ষেপ নিচ্ছে।

চূড়ান্ত প্রক্রিয়াটি আরও দেখতে লাগে:

  1. আপনার প্রক্রিয়া কল calloc()করে 256 এমআইবি চেয়েছে।

  2. মানক গ্রন্থাগারটি mmap()256 মাইবি কল করে asks

  3. কার্নেলটি 256 এমআইবি অব্যবহৃত অ্যাড্রেস স্পেসের সন্ধান করে, সেই ঠিকানা স্থানটি এখন কীসের জন্য ব্যবহৃত হয় এবং ফিরে আসে সে সম্পর্কে একটি নোট তৈরি করে।

  4. মান গ্রন্থাগার জানে যে ফল mmap()সবসময় শূণ্যসমূহ দিয়ে পূর্ণ (অথবা হতে হবে একবার এটা আসলে কিছু র্যাম পায়), তাই এটি মেমরি স্পর্শ করে না, তাই কোন পেজ ফল্ট, এবং র্যাম আপনার প্রক্রিয়া কখনো দেওয়া হয় ।

  5. আপনার প্রক্রিয়াটি অবশেষে প্রস্থান করে, এবং কার্নেলটি র‌্যাম পুনরায় দাবি করার প্রয়োজন হয় না কারণ এটি কখনই প্রথম স্থানে বরাদ্দ ছিল না।

আপনি যদি 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()?


7
@ ডায়েটরিচ: ডায়রিচের ভার্চুয়াল মেমরির ব্যাখ্যা ওএস সম্পর্কে একই শূন্য ভরাট পৃষ্ঠাটি কলোকের জন্য বহুবার বরাদ্দ করা চেক করা সহজ। প্রতিটি বরাদ্দ মেমরি পৃষ্ঠায় জাঙ্ক ডেটা লিখুন এমন কিছু লুপ যুক্ত করুন (প্রতি 500 বাইটে একটি বাইট লেখার জন্য যথেষ্ট হওয়া উচিত)। সামগ্রিক ফলাফলটি তখন আরও ঘনিষ্ঠ হওয়া উচিত কারণ সিস্টেমটি উভয় ক্ষেত্রেই ভিন্ন ভিন্ন পৃষ্ঠা বরাদ্দ করতে বাধ্য করা হবে।
ক্রিস করুন

1
@ ক্রিসস: প্রকৃতপক্ষে, যদিও প্রতিটি 4096 প্রতি বাইট সিস্টেমের বিশাল সংখ্যাগুরুতে যথেষ্ট
ডায়েট্রিচ এপ্প

প্রকৃতপক্ষে, calloc()প্রায়শই mallocবাস্তবায়ন স্যুটটির অংশ , এবং মেমরি পাওয়ার সময় কল না করার জন্য এটি অনুকূলিত । bzerommap
মীরাবিলোস

1
সম্পাদনা করার জন্য আপনাকে ধন্যবাদ, আমার মনে এটি প্রায় ছিল। প্রথমদিকে আপনি সর্বদা malloc + মেমসেটের পরিবর্তে কলোক ব্যবহার করতে বলেছেন। দয়া করে 1. ম্যালোক 2 এ ডিফল্ট হিসাবে স্টেট করুন the যদি বাফারের একটি ছোট অংশ শূন্য করা দরকার হয় তবে part অংশটি স্মরণ করুন otherwise অন্যথায় কলোক ব্যবহার করুন। বিশেষত পুরো আকারটি স্মরণে রাখবেন না (এটির জন্য কলোক ব্যবহার করুন) এবং ভ্যালগ্র্যান্ড এবং স্ট্যাটিক কোড বিশ্লেষকের মতো বিষয়গুলিতে বাধা সৃষ্টি করে (সমস্ত স্মৃতি হঠাৎ শুরু হয়ে যায়) সমস্ত কিছুর কলকে ডিফল্ট করবেন না NOT এটি বাদে আমি মনে করি এটি ঠিক আছে।
কর্মচারী

5
যদিও গতি সম্পর্কিত নয়, callocএটি বাগ প্রবণতাও কম। এটি হ'ল যেখানে large_int * large_intওভারফ্লো হবে, calloc(large_int, large_int)ফিরে আসবে NULLতবে malloc(large_int * large_int)এটি অপরিজ্ঞাত আচরণ, কারণ আপনি জানেন না যে মেমরি ব্লকের আসল আকারটি ফিরে আসবে।
ডুনস

12

কারণ অনেকগুলি সিস্টেমে, অতিরিক্ত প্রক্রিয়াজাতকরণের সময়, ওএস মুক্ত মেমরিটি নিজের থেকে শূন্যে সেট করে এবং এটিকে নিরাপদ হিসাবে চিহ্নিত করে calloc(), তাই যখন আপনি কল করবেন calloc(), এটি আপনাকে দিতে ইতিমধ্যে মুক্ত, জিরো মেমরি থাকতে পারে।


2
তুমি কি নিশ্চিত? কোন সিস্টেম এটি করে? আমি ভেবেছিলাম যে বেশিরভাগ ওএসগুলি প্রসেসর নিষ্ক্রিয় থাকাকালীন কেবল বন্ধ করে দেয় এবং সেই মেমরিটিতে লেখার সাথে সাথে বরাদ্দকৃত প্রক্রিয়াগুলির চাহিদা অনুযায়ী মেমরির শূন্য হয় (তবে তারা যখন এটি বরাদ্দ করে না তখন)।
ডায়েটারিচ এপ্পি

@ ডায়েটরিচ - নিশ্চিত নয় আমি এটি একবার শুনেছি এবং এটি calloc()আরও কার্যকর করার পক্ষে যুক্তিসঙ্গত (এবং যুক্তিসঙ্গত সহজ) উপায় বলে মনে হয়েছিল ।
ক্রিস লুৎজ

@ পিয়ারটেন - calloc()স্পেসিফিক অপ্টিমাইজেশনের উপর আমি কোনও ভাল তথ্য খুঁজে পাই না এবং আমি ওপি'র জন্য লিবিসি উত্স কোডটি ব্যাখ্যা করার মতো মনে করি না। এই অপ্টিমাইজেশানটি বিদ্যমান নয় / কাজ করে না তা দেখাতে আপনি কি কিছু সন্ধান করতে পারেন?
ক্রিস লুৎজ

13
@ ডায়েডরিচ: ফ্রিবিএসডি নিষ্ক্রিয় সময়ে পৃষ্ঠাগুলি শূন্য-পূরণের কথা: এর vm.idlezero_enable সেটিংটি দেখুন।
ঝ্যান লিংস

1
@ ডায়েরিচইপ নেক্রোকে দুঃখিত, তবে উদাহরণস্বরূপ উইন্ডোজ এটি করে।
আন্দ্রেয়াস গ্রেপেন্টিন

1

কিছু মোডে কিছু প্ল্যাটফর্মে malloc এটি ফিরে আসার পূর্বে মেমরিটিকে কিছুটা শূন্য-শূন্য মানের থেকে আরম্ভ করে, যাতে দ্বিতীয় সংস্করণটি মেমরিটিকে দু'বার ভালভাবে আরম্ভ করতে পারে

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.