ব্র্যাক () সিস্টেম কল কী করে?


184

লিনাক্স প্রোগ্রামার ম্যানুয়াল অনুসারে:

brk () এবং sbrk () প্রোগ্রাম বিরতির অবস্থান পরিবর্তন করে, যা প্রক্রিয়াটির ডেটা বিভাগের শেষ সংজ্ঞা দেয়।

এখানে ডেটা বিভাগের অর্থ কী? এটি কি কেবল ডেটা বিভাগ বা ডেটা, বিএসএস এবং হিপ মিলিত?

উইকির মতে:

কখনও কখনও ডেটা, বিএসএস এবং হিপ অঞ্চলগুলি সম্মিলিতভাবে "ডেটা বিভাগ" হিসাবে উল্লেখ করা হয়।

আমি কেবল ডেটা বিভাগের আকার পরিবর্তন করার কোনও কারণ দেখতে পাচ্ছি না। যদি এটি ডেটা, বিএসএস এবং সম্মিলিতভাবে হিপ হয় তবে গাদা আরও স্থান পাবে বলে এটি বোঝা যায়।

যা আমার দ্বিতীয় প্রশ্নের কাছে নিয়ে আসে। আমি এখনও অবধি পড়ে থাকা সমস্ত নিবন্ধগুলিতে লেখক বলেছেন যে গাদা wardর্ধ্বমুখী হয় এবং স্ট্যাকটি নীচের দিকে বৃদ্ধি পায়। তবে তারা যা ব্যাখ্যা করে না তা হ'ল গাদা এবং স্ট্যাকের মধ্যবর্তী সমস্ত স্থান দখল করলে কী ঘটে?

এখানে চিত্র বর্ণনা লিখুন


1
আপনি স্থানের বাইরে থাকলে আপনি কি করবেন? আপনি এইচডিডি তে বদলান। আপনি স্থান ব্যবহার করার পরে, আপনি অন্যান্য ধরণের তথ্যের জন্য এটি প্রকাশ করেন।
ইগরিস আজানোভাস

28
@ ইগরিস: আপনি শারীরিক স্মৃতি বিভ্রান্ত করছেন (যা আপনি ভার্চুয়াল মেমরি ব্যবহার করে প্রয়োজন অনুযায়ী ডিস্কে বদল করতে পারেন) এবং ঠিকানার স্থান । আপনি যখন নিজের ঠিকানার স্থান পূরণ করবেন, তখন কোনও পরিমাণ অদলবদল আপনাকে সেই ঠিকানাগুলি মাঝখানে ফেরত দেবে না।
ড্যানিয়েল প্রাইডেন

7
একটি অনুস্মারক হিসাবে, brk()সিস্টেম কল সি এর চেয়ে এসেম্বলি ভাষায় বেশি কার্যকর, কোনও ডেটা-বরাদ্দের উদ্দেশ্যে malloc()পরিবর্তে ব্যবহার করা উচিত brk()- তবে এটি প্রস্তাবিত প্রশ্নটিকে কোনওভাবেই অকার্যকর করে না।
alecov

2
@ ব্রায়ান: বিভিন্ন স্তরের এবং প্রান্তিককরণ, ফ্রি পুল ইত্যাদির ক্ষেত্রগুলি পরিচালনা করার জন্য হিপ একটি জটিল ডেটা কাঠামো Th বেশিরভাগ ওএসে, একটি পৃষ্ঠা বরাদ্দকারী অন্তর্নিহিত স্ট্যাকস, হিপ এবং মেমরি-ম্যাপযুক্ত ফাইল রয়েছে।
বেন ভয়েগট

2
@ ব্রায়ান: কে বলেছে যে কোনও "স্ট্যাক" চালিয়ে যাচ্ছে brk()এবং sbrk()? স্ট্যাকগুলি পৃষ্ঠার বরাদ্দকারী দ্বারা পরিচালিত হয়, অনেক নিম্ন স্তরে।
বেন ভয়েগ্ট

উত্তর:


231

ডায়াগ্রাম আপনি পোস্ট ইন, যে সময়টাতে ঠিকানা দ্বারা কাজে ব্যবহৃত "বিরতি" brkএবং sbrkগাদা উপরের ডটেড লাইন -is।

ভার্চুয়াল মেমরি বিন্যাসের সরলীকৃত চিত্র

আপনি যে ডকুমেন্টেশনটি পড়েছেন তা এটি "ডেটা বিভাগ" এর শেষ হিসাবে বর্ণনা করে কারণ traditionalতিহ্যবাহী (প্রাক-অংশীদারি-গ্রন্থাগারগুলি, প্রাক- mmap) ইউনিক্সে ডেটা বিভাগটি গাদা দিয়ে অবিচ্ছিন্ন ছিল; প্রোগ্রাম শুরুর আগে, কার্নেলটি ঠিকানা শূন্য থেকে শুরু করে "পাঠ্য" এবং "ডেটা" ব্লকগুলি র‍্যামে লোড করবে (আসলে ঠিক উপরে শূন্যের উপরে কিছুটা, যাতে ন্যূনাল পয়েন্টারটি সত্যিকার অর্থে কোনও বিষয় নির্দেশ করে না) এবং ব্রেক ঠিকানাটি সেট করে ডেটা বিভাগের সমাপ্তি। প্রথম কলে mallocতারপর ব্যবহার করেন sbrkবিরতি উপরে উঠানো এবং গাদা তৈরি করতে মাঝে যেমন ডায়াগ্রাম দেখানো, ডাটা সেগমেন্টের উপরে এবং নতুন, উচ্চ বিরতি ঠিকানা, এবং পরবর্তী ব্যবহারের mallocজন্য এটি ব্যবহার গাদা বড় করতে হবে প্রয়োজনীয় হিসাবে.

ইতিমধ্যে, স্ট্যাকটি মেমরির শীর্ষে শুরু হয় এবং নীচে বৃদ্ধি পায়। স্ট্যাকটিকে আরও বড় করতে সুস্পষ্ট সিস্টেম কলগুলির প্রয়োজন নেই; হয় এটি যতটা র‍্যাম বরাদ্দ করা যায় তার সাথেই এটি শুরু হয় (এটি ছিল গতানুগতিক পদ্ধতি) অথবা স্ট্যাকের নীচে সংরক্ষিত ঠিকানার একটি অঞ্চল রয়েছে, যেখানে সেখানে লেখার চেষ্টা লক্ষ্য করে যখন কার্নেল স্বয়ংক্রিয়ভাবে র‌্যাম বরাদ্দ করে (এটি আধুনিক পদ্ধতি)। যে কোনও উপায়ে, ঠিকানা জায়গার নীচে "গার্ড" অঞ্চল থাকতে পারে বা নাও থাকতে পারে যা স্ট্যাকের জন্য ব্যবহার করা যেতে পারে। যদি এই অঞ্চলটি বিদ্যমান থাকে (সমস্ত আধুনিক সিস্টেম এটি করে) এটি স্থায়ীভাবে আনম্যাপযুক্ত; যদি হয়স্ট্যাক বা গাদা এটিতে বাড়ার চেষ্টা করে, আপনি একটি সেগমেন্টেশন ত্রুটি পান। Ditionতিহ্যগতভাবে, যদিও, কার্নেল একটি সীমানা প্রয়োগের জন্য কোনও প্রচেষ্টা করেনি; স্ট্যাকটি গাদা হয়ে উঠতে পারে, বা স্তূপটি স্ট্যাকের মধ্যে বাড়তে পারে এবং উভয় উপায়ে তারা একে অপরের ডেটা নিয়ে স্ক্র্যাবল করে এবং প্রোগ্রামটি ক্র্যাশ হয়ে যায়। আপনি খুব ভাগ্যবান হলে এটি অবিলম্বে ক্রাশ হবে।

আমি নিশ্চিত নই যে এই চিত্রটিতে 512 জিবি নম্বরটি এসেছে। এটি একটি 64-বিট ভার্চুয়াল ঠিকানার স্থান বোঝায় যা আপনার কাছে থাকা খুব সাধারণ মেমরি মানচিত্রের সাথে সঙ্গতিপূর্ণ নয়। একটি আসল -৪-বিট ঠিকানার স্থানটি আরও দেখতে দেখতে:

কম সরলীকৃত ঠিকানার স্থান

              Legend:  t: text, d: data, b: BSS

এটি দূরবর্তীভাবে স্কেল করা যায় না, এবং কোনও প্রদত্ত ওএস কীভাবে স্টাফ করে তা হ'ল ব্যাখ্যা করা উচিত নয় (আমি এটি আবিষ্কার করার পরে আমি আবিষ্কার করেছি যে লিনাক্স বাস্তবে এক্সিকিউটেবলকে শূন্যের ঠিকানার চেয়ে বেশি করে দিয়েছে যা আমি ভেবেছি তার চেয়ে বেশি ভাগ করা লাইব্রেরি আশ্চর্যজনকভাবে উচ্চ ঠিকানাগুলিতে)। এই চিত্রের কালো অঞ্চলগুলি আনম্যাপ করা আছে - যে কোনও অ্যাক্সেসের ফলে তাত্ক্ষণিক সেগফল্ট হয় - এবং এগুলি ধূসর অঞ্চলের তুলনায় বিশাল । হালকা-ধূসর অঞ্চলগুলি হ'ল প্রোগ্রাম এবং এর ভাগ করা লাইব্রেরি (সেখানে কয়েক ডজন শেয়ার্ড লাইব্রেরি থাকতে পারে); প্রত্যেকের একটি স্বতন্ত্র আছেপাঠ্য এবং ডেটা বিভাগ (এবং "বিএসএস" বিভাগ, যা বৈশ্বিক ডেটাও ধারণ করে তবে ডিস্কে এক্সিকিউটেবল বা লাইব্রেরিতে স্থান গ্রহণের পরিবর্তে অল-বিট-শূন্যে শুরু করা হয়)। এক্সিকিউটেবলের ডেটা বিভাগে গাদা আর অবিচ্ছিন্নভাবে অবিচ্ছিন্ন থাকে না - আমি এটি সেভাবে আঁকলাম, তবে এটি লিনাক্সের মতো দেখায়, কমপক্ষে, এটি করে না। স্ট্যাকটি আর ভার্চুয়াল অ্যাড্রেস স্পেসের শীর্ষে টিকে থাকবে না এবং গাদা এবং স্ট্যাকের মধ্যে দূরত্ব এতটাই বিশাল যে আপনাকে এটি পেরিয়ে যাওয়ার বিষয়ে চিন্তা করতে হবে না।

বিরতি এখনও স্তূপের উপরের সীমা। যাইহোক, আমি যা দেখিনি তা হ'ল কালো জায়গায় মেমরির কয়েক ডজন স্বতন্ত্র বরাদ্দ থাকতে পারে যেখানে তার mmapপরিবর্তে তৈরি করা হয়েছে brk। (ওএস এগুলি brkঅঞ্চল থেকে দূরে রাখার চেষ্টা করবে যাতে তারা সংঘর্ষ না করে।)


7
বিস্তারিত ব্যাখ্যার জন্য +1। আপনি কি জানেন যে mallocএখনও নির্ভর করে brkবা এটি mmapপৃথক মেমরি ব্লক "ফিরিয়ে দিতে" সক্ষম হতে ব্যবহার করছে কিনা?
অ্যান্ডারস আবেল

18
এটা তোলে নির্দিষ্ট বাস্তবায়ন উপর নির্ভর করে, কিন্তু IIUC বর্তমান অনেকটা mallocগুলি ব্যবহার brkছোট বরাদ্দ এবং স্বতন্ত্র এলাকার mmapবৃহৎ জন্য গুলি (বলুন,> 128k) বরাদ্দ। উদাহরণস্বরূপ, লিনাক্স ম্যানপেজে MMAP_THRESHOLD এর আলোচনা দেখুন malloc(3)
zwol

1
প্রকৃতপক্ষে একটি ভাল ব্যাখ্যা। তবে আপনি যেমন বলেছিলেন যে স্ট্যাকটি আর ভার্চুয়াল ঠিকানা জায়গার শীর্ষে বসে না। এটি কি কেবলমাত্র bit৪ বিট অ্যাড্রেস স্পেসের ক্ষেত্রে সত্য বা 32 বিট অ্যাড্রেস স্পেসের ক্ষেত্রেও এটি সত্য। এবং যদি স্ট্যাকটি ঠিকানার জায়গার শীর্ষে বসে থাকে তবে বেনামী মেমরি মানচিত্রগুলি কোথায় ঘটে? এটি স্ট্যাকের ঠিক আগে ভার্চুয়াল ঠিকানার জায়গার শীর্ষে রয়েছে।
নিক

3
@ নিখিল: এটি জটিল। বেশিরভাগ 32-বিট সিস্টেমগুলি স্ট্যাকটিকে ব্যবহারকারী-মোড অ্যাড্রেস স্পেসের একেবারে শীর্ষে রাখে , যা প্রায়শই পুরো ঠিকানা জায়গার নীচের 2 বা 3 জি থাকে (অবশিষ্ট স্থান কার্নেলের জন্য সংরক্ষিত থাকে)। আমি বর্তমানে এমন একটি সম্পর্কে ভাবতে পারি না যা আমি জানি না তবে আমি তাদের সব জানি না। বেশিরভাগ -৪-বিট সিপিইউ আসলে আপনাকে পুরো -৪-বিট স্পেস ব্যবহার করতে দেয় না; ঠিকানার 10 থেকে 16 বিটের উচ্চতম শূন্য বা সমস্ত হতে হবে। স্ট্যাকটি সাধারণত ব্যবহারযোগ্য কম ঠিকানাগুলির শীর্ষের কাছে স্থাপন করা হয়। আমি আপনাকে একটি বিধি দিতে পারি না mmap; এটি অত্যন্ত ওএস-নির্ভর
zwol

3
@ রিকার্ডোবেস্টেটি এটি ঠিকানার জায়গার অপচয় করে , তবে তা ক্ষতিদায়ক নয় - একটি -৪ -বিট ভার্চুয়াল অ্যাড্রেস স্পেস এত বড় যে আপনি যদি প্রতি সেকেন্ডে একটি গিগাবাইটের মাধ্যমে জ্বালিয়ে ফেলেন তবে আপনার রান আউট হতে 500 বছর লাগবে would [1] বেশিরভাগ প্রসেসর এমনকি ভার্চুয়াল ঠিকানার 2 ^ 48 থেকে 2 ^ 53 বিটেরও বেশি ব্যবহারের অনুমতি দেয় না (হ্যাশ পেজ টেবিল মোডে POWER4 হ'ল একমাত্র ব্যতিক্রম)। এটি শারীরিক র্যাম নষ্ট করে না; অব্যবহৃত ঠিকানাগুলি র‍্যামের জন্য বরাদ্দ করা হয় না।
zwol

26

ন্যূনতম চলমান উদাহরণ

ব্র্যাক () সিস্টেম কল কী করে?

কর্নেলকে জিজ্ঞাসা করে যে আপনাকে হিপ বলা মেমরির একটি স্বল্প অংশ পড়তে এবং লিখতে দেয়।

আপনি যদি না জিজ্ঞাসা করেন তবে এটি আপনাকে সেগফল্ট করতে পারে।

ছাড়া brk:

#define _GNU_SOURCE
#include <unistd.h>

int main(void) {
    /* Get the first address beyond the end of the heap. */
    void *b = sbrk(0);
    int *p = (int *)b;
    /* May segfault because it is outside of the heap. */
    *p = 1;
    return 0;
}

সহ brk:

#define _GNU_SOURCE
#include <assert.h>
#include <unistd.h>

int main(void) {
    void *b = sbrk(0);
    int *p = (int *)b;

    /* Move it 2 ints forward */
    brk(p + 2);

    /* Use the ints. */
    *p = 1;
    *(p + 1) = 2;
    assert(*p == 1);
    assert(*(p + 1) == 2);

    /* Deallocate back. */
    brk(b);

    return 0;
}

গিটহাব উজানের দিকে

brkউপরেরটি কোনও নতুন পৃষ্ঠাতে আঘাত না করে এমনকি সেগফ্লটকে নাও মেরে ফেলতে পারে, সুতরাং এখানে আরও আক্রমণাত্মক সংস্করণ দেওয়া হয়েছে যা ১M এমআইবি বরাদ্দ করে এবং সেগফোল্ট ছাড়াই খুব সম্ভবত brk:

#define _GNU_SOURCE
#include <assert.h>
#include <unistd.h>

int main(void) {
    void *b;
    char *p, *end;

    b = sbrk(0);
    p = (char *)b;
    end = p + 0x1000000;
    brk(end);
    while (p < end) {
        *(p++) = 1;
    }
    brk(b);
    return 0;
}

উবুন্টু 18.04 এ পরীক্ষিত।

ভার্চুয়াল ঠিকানার স্থানের দৃশ্যায়ন

আগে brk:

+------+ <-- Heap Start == Heap End

পরে brk(p + 2):

+------+ <-- Heap Start + 2 * sizof(int) == Heap End 
|      |
| You can now write your ints
| in this memory area.
|      |
+------+ <-- Heap Start

পরে brk(b):

+------+ <-- Heap Start == Heap End

ঠিকানার জায়গাগুলি আরও ভালভাবে বুঝতে, আপনার নিজের পেজিংয়ের সাথে পরিচিত হওয়া উচিত: x86 পেজিং কীভাবে কাজ করে?

কেন আমরা প্রয়োজন উভয় না brkএবং sbrk?

brkঅবশ্যই sbrk+ অফসেট গণনা দ্বারা বাস্তবায়িত হতে পারে , উভয়ই কেবল সুবিধার জন্য বিদ্যমান।

ব্যাকএন্ডে, লিনাক্স কার্নেল v5.0 এর একটি একক সিস্টেম কল রয়েছে brkযা উভয়ই প্রয়োগ করতে ব্যবহৃত হয়: https://github.com/torvalds/linux/blob/v5.0/arch/x86/entry/syscalls/syscall_64 উভয়ই প্রয়োগ করতে । tbl # L23

12  common  brk         __x64_sys_brk

brkপসিক্স কি ?

brkপসিক্স হিসাবে ব্যবহৃত হত, তবে এটি পসিক্স 2001-এ সরিয়ে ফেলা হয়েছিল, সুতরাং _GNU_SOURCEগ্লিবসি মোড়কে অ্যাক্সেসের প্রয়োজন ।

অপসারণ সম্ভবত প্রবর্তনের কারণে ঘটে mmapযা একটি সুপারসেট যা একাধিক পরিসর বরাদ্দ করতে এবং আরও বেশি বরাদ্দকরণের বিকল্প দেয়।

আমি মনে করি যে আজকাল আপনার brkপরিবর্তে mallocবা আপনার ব্যবহার করা উচিত এমন কোনও বৈধ মামলা নেই mmap

brk বনাম malloc

brkবাস্তবায়ন এক পুরানো সম্ভাবনা malloc

mmapএটি আরও শক্তিশালী আরও শক্তিশালী প্রক্রিয়া যা সম্ভবত সমস্ত পসিক্স সিস্টেম বর্তমানে প্রয়োগ করতে ব্যবহার করে malloc। এখানে একটি ন্যূনতম চলমানযোগ্য mmapমেমরি বরাদ্দ উদাহরণ

আমি মিক্স brkএবং malloc করতে পারেন ?

যদি আপনার সাথে mallocএটি প্রয়োগ করা হয় brk, তবে কীভাবে এটি সম্ভবত জিনিসগুলিকে উড়িয়ে দিতে পারে না সে সম্পর্কে আমার কোনও ধারণা নেই, যেহেতু brkকেবলমাত্র একক পরিসরে মেমরি পরিচালনা করে।

তবে গ্লিবসি ডক্সে আমি এটি সম্পর্কে কিছুই খুঁজে পাইনি, যেমন:

জিনিসগুলি সম্ভবত সেখানে কাজ করবে বলে আমি মনে করি যেহেতু mmapসম্ভবত এটি ব্যবহার করা হয়েছে malloc

আরো দেখুন:

অধিক তথ্য

অভ্যন্তরীণভাবে, কার্নেল সিদ্ধান্ত নিয়েছে যে প্রক্রিয়াটিতে এত বেশি মেমরি থাকতে পারে এবং সেই ব্যবহারের জন্য এয়ারমার্ক মেমরি পৃষ্ঠা রয়েছে

এটি ব্যাখ্যা করে যে স্ট্যাকটি কীভাবে স্তূপের সাথে তুলনা করে: x86 অ্যাসেমব্লিতে রেজিস্টারগুলিতে ব্যবহৃত পুশ / পপ নির্দেশাবলীর কাজ কী?


4
যেহেতু pটাইপ করার জন্য একটি পয়েন্টার int, তাই এটি করা উচিত নয় brk(p + 2);?
জোহান বুলি

ছোট দ্রষ্টব্য: আক্রমণাত্মক সংস্করণটির লুপে *(p + i) = 1;
প্রকাশটি

যাইহোক, কেন brk(p + 2)কেবল এটিকে আরও বাড়ানোর পরিবর্তে একটি ব্যবহার করা দরকার sbrk(2)? Brk কি আসলেই প্রয়োজনীয়?
ইয়ি লিন লিউ

1
@ ইলিনলিউইউ আমি মনে করি এটি একটি মাত্র কার্নেল ব্যাকএন্ড ( brkসিস্কেল) এর জন্য কেবল দুটি খুব একই সি সীমান্ত । brkপূর্বে বরাদ্দ স্ট্যাক পুনরুদ্ধার করতে কিছুটা বেশি সুবিধাজনক।
সিরো সান্তিলি :0 冠状 病 六四 事件

1
@ সিরোস্যান্টিলি 改造 改造 中心 996ICU 事件 int ইন্টের আকার 4 বাইট এবং একটি ইন্টের আকার 4 বাইট হিসাবে (32 বিট মেশিনে) বিবেচনা করে আমি ভাবছিলাম যে এটি কেবল 4 বাইট দ্বারা বাড়ানো উচিত নয় (পরিবর্তে) 8 - (2 * আকারের পূর্বে))। এটি পরবর্তী উপলব্ধ হিপ সঞ্চয়স্থানের দিকে নির্দেশ করা উচিত নয় - যা 4 বাইট দূরে (8 নয়) হবে। আমি এখানে কিছু অনুপস্থিত থাকলে আমাকে সংশোধন করুন।
সাকেত শারদ

10

"Malloc ওভারহেড" এড়াতে আপনি সর্বদা নিজেরাই নিজেকে ব্যবহার করতে পারেন brkএবং sbrkযারাই সর্বদা অভিযোগ করে। তবে আপনি সহজেই এই পদ্ধতিটি সংক্ষেপে ব্যবহার করতে পারবেন না mallocতাই আপনার যখন freeকিছুই করার দরকার নেই তখনই এটি উপযুক্ত । কারণ আপনি পারবেন না। এছাড়াও, আপনার mallocঅভ্যন্তরীণভাবে ব্যবহারযোগ্য কোনও লাইব্রেরি কল এড়ানো উচিত । অর্থাৎ। strlenসম্ভবত নিরাপদ, কিন্তু fopenসম্ভবত না।

sbrkআপনি যেমন কল করবেন ঠিক তেমন কল করুন malloc। এটি বর্তমান বিরতিতে একটি পয়েন্টার দেয় এবং সেই পরিমাণ দ্বারা ব্রেককে বাড়িয়ে তোলে।

void *myallocate(int n){
    return sbrk(n);
}

আপনি স্বতন্ত্র বরাদ্দগুলি মুক্ত করতে পারবেন না (কারণ কোনও ম্যালোক-ওভারহেড নেই , মনে রাখবেন), আপনি প্রথম কলটিতে ফিরে আসা মানটি দিয়ে কল করে পুরো স্থানটি মুক্ত করতে পারবেন , এইভাবে ব্রকে রিওয়াইন্ডিং করুনbrksbrk

void *memorypool;
void initmemorypool(void){
    memorypool = sbrk(0);
}
void resetmemorypool(void){
    brk(memorypool);
}

এমনকি আপনি এই অঞ্চলগুলিকে স্তুপ করতে পারেন, অঞ্চলটির শুরুতে ব্রেকটি রিওয়ার্ড করে অতি সাম্প্রতিক অঞ্চলটিকে ত্যাগ করতে পারেন।


আরেকটা জিনিস ...

sbrkকোড গল্ফেও এটি দরকারী কারণ এটি 2 টির চেয়ে কম অক্ষর malloc


7
-1 কারণ: malloc/ সম্ভবত freeঅবশ্যই ওএসকে মেমরি ফিরিয়ে দিতে পারে (এবং করবে)। আপনি যখন চান তখন তারা সর্বদা এটি না করতে পারে তবে আপনার ব্যবহারের ক্ষেত্রে অসম্পূর্ণভাবে সুরক্ষিত হওয়ার বিষয়টি হিউরিস্টিকের বিষয়। আরও গুরুত্বপূর্ণ বিষয়, যে কোনও প্রোগ্রামে কল করুন sbrkএমন কোনও ননজারো যুক্তি দিয়ে কল করা নিরাপদmalloc নয় - এবং প্রায় সমস্ত সি লাইব্রেরির ফাংশনকে mallocঅভ্যন্তরীণভাবে কল করার অনুমতি দেওয়া হয় । কেবলমাত্র সেইগুলিই হ'ল অ্যাসিঙ্ক-সিগন্যাল-নিরাপদ ফাংশন।
zwol

এবং "এটি অনিরাপদ" এর অর্থ, "আপনার প্রোগ্রামটি ক্রাশ হবে।"
zwol

আমি ফিরে আসা স্মৃতি গর্ব সরিয়ে সম্পাদনা করেছি এবং অভ্যন্তরীণভাবে লাইব্রেরি কার্যকারিতা বিপদের কথা উল্লেখ করেছি malloc
লুসার droog

1
আপনি যদি অভিনব মেমরি বরাদ্দ করতে চান তবে এটি ম্যালোকের শীর্ষে অথবা এমএমএপের শীর্ষে করুন। ব্রাক এবং এসবিআরকে স্পর্শ করবেন না, এগুলি অতীত থেকে রইল যা ভালোর চেয়ে আরও বেশি ক্ষতি করে (এমনকি ম্যান্যাপগুলি আপনাকে সেগুলি পরিষ্কার রাখতে বলে!)
এলফ

3
এটা বোকামি. যদি আপনি প্রচুর ছোট বরাদ্দের জন্য ম্যালোক ওভারহেড এড়াতে চান তবে একটি বড় বরাদ্দ ( মলোক বা এমএমএপ সহ , এসআরবিকে নয় ) করুন এবং নিজেই এটি ডোল করুন। যদি আপনি আপনার বাইনারি গাছের নোডগুলি একটি অ্যারেতে রাখেন তবে আপনি 64 বি পয়েন্টারের পরিবর্তে 8 বি বা 16 বি সূচক ব্যবহার করতে পারেন। আপনি সমস্ত নোড মোছার জন্য প্রস্তুত না হওয়া পর্যন্ত আপনাকে কোনও নোড মুছতে হবে না যখন এটি দুর্দান্ত কাজ করে। (যেমন, ফ্লাইয়ে বাছাই করা অভিধান তৈরি করুন)) এর sbrkজন্য ব্যবহার করা কেবল কোড-গল্ফের জন্যই দরকারী, কারণ mmap(MAP_ANONYMOUS)উত্স-কোডের আকার বাদে ম্যানুয়ালি ব্যবহার করা প্রতিটি উপায়েই ভাল।
পিটার কর্ডস

3

একটি বিশেষ মনোনীত বেনামে প্রাইভেট মেমরি ম্যাপিং রয়েছে (traditionতিহ্যগতভাবে ডাটা / বিএসের বাইরেও অবস্থিত, তবে আধুনিক লিনাক্স আসলে এএসএলআরের সাথে অবস্থানটি সামঞ্জস্য করবে)। নীতিগতভাবে এটি অন্য যে কোনও ম্যাপিং দিয়ে আপনি তৈরি করতে পারেন তার চেয়ে ভাল mmapনয়, তবে লিনাক্সের কিছু অপ্টিমাইজেশন রয়েছে যা এই ম্যাপিংটির brkশেষটি ( সিস্কেল ব্যবহার করে ) হ্রাস করা লকিং ব্যয়ের সাথে সামঞ্জস্য করে mmapবা কী কী mremapহবে তার তুলনায় উপরের দিকে বাড়ানো সম্ভব করে তোলে । এটি mallocমূল হিপ বাস্তবায়নের সময় প্রয়োগের জন্য এটি আকর্ষণীয় করে তোলে ।


আপনি এই ম্যাপিংয়ের শেষটি উপরের দিকে প্রসারিত করা সম্ভব করেছিলেন, হ্যাঁ?
zwol

হ্যাঁ, স্থির এর জন্যে দুঃখিত!
আর .. গিটহাব বন্ধ করুন ICE

0

আমি আপনার দ্বিতীয় প্রশ্নের উত্তর দিতে পারি। ম্যালোক ব্যর্থ হবে এবং একটি নাল পয়েন্টার ফিরিয়ে দেবে। গতিশীলভাবে মেমরি বরাদ্দ করার সময় আপনি সর্বদা নাল পয়েন্টারটি পরীক্ষা করেন।


তাহলে ব্রক এবং এসবিআরকের ব্যবহার কী?
নিক

3
@ নিখিল রাঠোদ: এবং / অথবা হুডের নীচে malloc()ব্যবহার করবে - এবং আপনি নিজের কাস্টমাইজড সংস্করণটি নিজেরাই প্রয়োগ করতে চাইলে আপনিও করতে পারেন । brk()sbrk()malloc()
ড্যানিয়েল প্রাইডেন

@ ড্যানিয়েল প্রাইডেন: উপরের চিত্রের মতো স্ট্যাক এবং ডেটা বিভাগের মধ্যে থাকা অবস্থায় কীভাবে স্তূপে ব্র্যাক এবং এসবিআরকে কাজ করতে পারে। এই কাজ করার জন্য গাদা শেষ হওয়া উচিত। আমি কি সঠিক?
নিক

2
@ ব্রায়ান: ড্যানিয়েল বলেছিলেন যে ওএস স্ট্যাক সেগমেন্ট পরিচালনা করে , স্ট্যাক পয়েন্টারটি নয় ... খুব আলাদা জিনিস। মুল বক্তব্যটি হ'ল স্ট্যাক সেগমেন্টের জন্য কোনও এসবিআরকে / ব্রেক সিস্কাল নেই - স্ট্যাক সেগমেন্টের শেষে লেখার চেষ্টা করার পরে লিনাক্স স্বয়ংক্রিয়ভাবে পৃষ্ঠা বরাদ্দ করে।
জিম বাল্টার

1
এবং ব্রায়ান, আপনি কেবল প্রশ্নের অর্ধেক উত্তর দিয়েছেন। অন্য অর্ধটি হ'ল যদি স্থান না পাওয়া যায় তখন আপনি স্ট্যাকের দিকে ঠেলাঠেলি করার চেষ্টা করেন ... আপনি একটি সেগমেন্টেশন ত্রুটি পান।
জিম বাল্টার

0

গাদাটি প্রোগ্রামের ডেটা বিভাগে সর্বশেষে রাখা হয়। brk()গাদা আকার পরিবর্তন করতে (প্রসারিত) করতে ব্যবহৃত হয়। যখন গাদাটি আর বাড়তে পারে না তখন কোনও mallocকল ব্যর্থ হবে।


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

2
@ নিকখিল মনে রাখবেন যে সেই চিত্রের শীর্ষটি স্মৃতিটির শেষ । স্ট্যাকটি বড় হওয়ার সাথে সাথে স্ট্যাকের শীর্ষটি ডায়াগ্রামের দিকে নীচের দিকে চলে যায়। স্তূপের শীর্ষটি প্রসারিত হওয়ার সাথে সাথে ডায়াগ্রামের উপরের দিকে চলে যায় ।
ব্রায়ান গর্ডন

0

ডেটা বিভাগটি মেমরির সেই অংশ যা আপনার সমস্ত স্থিতিশীল ডেটা ধরে রাখে, প্রবর্তনকালে এক্সিকিউটেবলের থেকে পড়ে এবং সাধারণত শূন্য-ভরা থাকে।


এটিতে অস্বীকারহীন স্ট্যাটিক ডেটাও রয়েছে (এক্সিকিউটেবলের কাছে উপস্থিত নেই) যা আবর্জনা হতে পারে।
লুসার droog

.bssপ্রোগ্রাম শুরুর আগে অবিশ্রান্ত স্ট্যাটিক ডেটা ( ) ওএস দ্বারা অল-বিট-শূন্যে আরম্ভ করা হয়; এটি আসলে সি স্ট্যান্ডার্ড দ্বারা গ্যারান্টিযুক্ত। কিছু এম্বেড থাকা সিস্টেমগুলি সম্ভবত মাথা ঘামায় না, আমি মনে করি (আমি এর আগে কখনও দেখিনি, তবে এমবেড থাকা
সমস্তটিই

@ জওয়ল: লিনাক্সের শূন্য পৃষ্ঠাগুলি দ্বারা ফিরে না আসার জন্য একটি সংকলন-সময় বিকল্প রয়েছে mmap, তবে আমি ধরে নিই যে .bssএটি এখনও শূন্য হবে। কোনও প্রোগ্রাম কিছু জিরোড অ্যারে চায় তা প্রকাশ করার জন্য সম্ভবত বিএসএস স্পেসটি সবচেয়ে সংক্ষিপ্ত উপায়।
পিটার কর্ডস

1
@ পিটারকর্ডস সি স্ট্যান্ডার্ড যা বলেছে তা হ'ল কোনও ইনিশিয়ালাইজার ছাড়াই ঘোষিত গ্লোবাল ভেরিয়েবলগুলিকে শূন্য হিসাবে আরম্ভ করা হিসাবে বিবেচনা করা হবে। এসি বাস্তবায়ন যা এই ধরণের পরিবর্তনশীলগুলিকে রাখে .bssএবং শূন্য নয় .bssতাই নন -কনফর্মিং হবে। কিন্তু কোনও কিছুই সি প্রয়োগকারীকে একেবারেই ব্যবহার করতে বাধ্য .bssকরে না এমনকি এমন জিনিস রাখে না।
zwol

@ পিটারকর্ডস এছাড়াও, "সি বাস্তবায়ন" এবং প্রোগ্রামের মধ্যে লাইনটি খুব ঝাপসা হতে পারে, উদাহরণস্বরূপ বাস্তবায়ন থেকে কোডের একটি ছোট অংশ থাকে, প্রতিটি নির্বাহযোগ্যের সাথে স্ট্যাটিকভাবে সংযুক্ত থাকে, যা আগে চলে main; এই কোডটি .bssকার্নেলটি না করানোর চেয়ে অঞ্চলটি শূন্য করতে পারে এবং এটি এখনও মেনে চলবে।
zwol

0

malloc মেমরি বরাদ্দ করতে brk সিস্টেম কল ব্যবহার করে।

অন্তর্ভুক্ত করা

int main(void){

char *a = malloc(10); 
return 0;
}

স্ট্রেস সহ এই সাধারণ প্রোগ্রামটি চালান, এটি ব্রেক সিস্টেমকে কল করবে।

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