মেমরি ফাঁস খুঁজতে আমি কীভাবে ভালগ্রাইন্ড ব্যবহার করব?


182

কোন প্রোগ্রামে মেমরি ফাঁস পেতে আমি কীভাবে ভালগ্রাইন্ড ব্যবহার করব?

দয়া করে কেউ আমাকে সহায়তা করুন এবং পদ্ধতিটি সম্পাদনের পদক্ষেপগুলি বর্ণনা করুন?

আমি উবুন্টু 10.04 ব্যবহার করছি এবং আমার একটি প্রোগ্রাম রয়েছে a.c, দয়া করে আমাকে সাহায্য করুন।


16
আপনি আপনার সংকলিত প্রোগ্রামটি পরীক্ষা করতে ভ্যালগ্রাইন্ড ব্যবহার করেন, উত্স কোড নয়।
টনি

6
@ রেজিডি নীচে প্রদত্ত উত্তরটি সঠিক, আপনি কেন তা গ্রহণ করেন না?
প্রতীক সিংহল

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

1
সম্পর্কিত: কোন টুল দিয়ে: stackoverflow.com/questions/6261201/...
সিরো Santilli郝海东冠状病六四事件法轮功

উত্তর:


297

কীভাবে ভালগ্র্যান্ড চালাবেন

ওপিকে অপমান করার জন্য নয়, তবে যারা এই প্রশ্নে আসে এবং এখনও লিনাক্সে নতুন তারা আপনাকে আপনার সিস্টেমে ভালগ্রিড ইনস্টল করতে হতে পারে

sudo apt install valgrind  # Ubuntu, Debian, etc.
sudo yum install valgrind  # RHEL, CentOS, Fedora, etc.

Valgrind- র সি / সি ++ কোড নির্দ্ধিধায় ব্যবহারযোগ্য, কিন্তু যখন সঠিকভাবে (দেখুন কনফিগার এমনকি অন্যান্য ভাষার জন্য ব্যবহার করা যেতে পারে এই পাইথন জন্য)।

ভালগ্রিড চালানোর জন্য , এক্সিকিউটেবলকে আর্গুমেন্ট হিসাবে পাস করুন (প্রোগ্রামটিতে কোনও প্যারামিটার সহ)।

valgrind --leak-check=full \
         --show-leak-kinds=all \
         --track-origins=yes \
         --verbose \
         --log-file=valgrind-out.txt \
         ./executable exampleParam1

পতাকাগুলি সংক্ষেপে,

  • --leak-check=full: "প্রতিটি পৃথক ফাঁস বিস্তারিতভাবে দেখানো হবে"
  • --show-leak-kinds=all: "সম্পূর্ণ" প্রতিবেদনে সমস্ত "নির্দিষ্ট, অপ্রত্যক্ষ, সম্ভব, পৌঁছনীয়" লিক ধরণের সমস্ত দেখান।
  • --track-origins=yes: গতি ওভার কার্যকর আউটপুট পছন্দ। এটি অস্বীকারহীন মানগুলির উত্স ট্র্যাক করে, যা মেমরির ত্রুটির জন্য খুব কার্যকর হতে পারে। যদি ভালগ্রাইন্ড অগ্রহণযোগ্যভাবে ধীর হয় তবে অফ করার কথা বিবেচনা করুন।
  • --verbose: আপনার প্রোগ্রামের অস্বাভাবিক আচরণ সম্পর্কে আপনাকে বলতে পারি। আরও ভার্বোসিটির জন্য পুনরাবৃত্তি করুন।
  • --log-file: একটি ফাইল লিখুন। কার্যকর যখন আউটপুট টার্মিনাল স্থান অতিক্রম করে।

শেষ পর্যন্ত, আপনি একটি ভালগ্রাইন্ড প্রতিবেদন দেখতে চান যা দেখতে এরকম দেখাচ্ছে:

HEAP SUMMARY:
    in use at exit: 0 bytes in 0 blocks
  total heap usage: 636 allocs, 636 frees, 25,393 bytes allocated

All heap blocks were freed -- no leaks are possible

ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

আমার একটা ফুটো আছে তবে কোথায় ?

সুতরাং, আপনার একটি মেমরি ফুটো হয়েছে, এবং ভ্যালগ্রিন্ড কোনও অর্থবহ কথা বলছে না। সম্ভবতঃ এরকম কিছু:

5 bytes in 1 blocks are definitely lost in loss record 1 of 1
   at 0x4C29BE3: malloc (vg_replace_malloc.c:299)
   by 0x40053E: main (in /home/Peri461/Documents/executable)

আমিও লিখেছি সি কোড একবার দেখুন:

#include <stdlib.h>

int main() {
    char* string = malloc(5 * sizeof(char)); //LEAK: not freed!
    return 0;
}

ঠিক আছে, 5 বাইট হারিয়েছিল। এটা কিভাবে ঘটেছে? ত্রুটি রিপোর্টটি ঠিক বলেছেন mainএবং malloc। একটি বৃহত্তর প্রোগ্রামে, এটি শিকার করতে মারাত্মক ঝামেলা হবে। এটি কীভাবে এক্সিকিউটেবলকে সংকলিত হয়েছিল । আমরা আসলে কী ভুল হয়েছে সে সম্পর্কে লাইন বাই লাইন বিশদ পেতে পারি। একটি ডিবাগ পতাকা দিয়ে আপনার প্রোগ্রামটি পুনরায় রচনা করুন (আমি এখানে ব্যবহার করছি gcc):

gcc -o executable -std=c11 -Wall main.c         # suppose it was this at first
gcc -o executable -std=c11 -Wall -ggdb3 main.c  # add -ggdb3 to it

এখন এই ডিবাগ বিল্ডটির সাথে, ভ্যালগ্রাইন্ড ফাঁস হওয়া মেমরির বরাদ্দকৃত কোডের সঠিক লাইনের দিকে নির্দেশ করে ! (শব্দবন্ধটি গুরুত্বপূর্ণ: আপনার ফুটোটি ঠিক এটির জায়গায় নাও হতে পারে তবে কী ফাঁস হয়েছিল The ট্রেসটি আপনাকে কোথায় খুঁজে পেতে সহায়তা করে ))

5 bytes in 1 blocks are definitely lost in loss record 1 of 1
   at 0x4C29BE3: malloc (vg_replace_malloc.c:299)
   by 0x40053E: main (main.c:4)

মেমরি ফুটো এবং ত্রুটিগুলি ডিবাগ করার কৌশলগুলি

  • Www.cplsplus.com ব্যবহার করুন ! এটিতে সি / সি ++ ফাংশনে দুর্দান্ত ডকুমেন্টেশন রয়েছে।
  • মেমরি ফাঁসের জন্য সাধারণ পরামর্শ:
    • আপনার গতিশীল বরাদ্দ মেমরিটি আসলে মুক্তি পেয়েছে তা নিশ্চিত করুন।
    • মেমরি বরাদ্দ করবেন না এবং পয়েন্টার নির্ধারণ করতে ভুলবেন না।
    • পুরানো মেমরিটি মুক্ত না হলে একটি পয়েন্টারকে নতুন দিয়ে ওভাররাইট করবেন না।
  • স্মৃতি ত্রুটির জন্য সাধারণ পরামর্শ:
    • আপনার ঠিকানা এবং সূচকগুলিতে অ্যাক্সেস এবং লেখার বিষয়ে নিশ্চিত আপনি নিজেরাই to স্মৃতি ত্রুটি ফাঁস থেকে পৃথক; তারা প্রায়শই কেবল IndexOutOfBoundsException সমস্যাগুলি টাইপ করে।
    • এটিকে মুক্ত করার পরে মেমোরিতে অ্যাক্সেস বা লিখবেন না।
  • কখনও কখনও আপনার ফাঁস / ত্রুটিগুলি একে অপরের সাথে যুক্ত হতে পারে, অনেকটা আইডিই আবিষ্কার করে যে আপনি এখনও বন্ধের বন্ধনী টাইপ করেন নি। একটি ইস্যু সমাধান করা অন্যকে সমাধান করতে পারে, সুতরাং ভাল অপরাধী মনে হয় এমন একটি সন্ধান করুন এবং এর মধ্যে কয়েকটি ধারণাকে প্রয়োগ করুন:

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

কমন লিকস এবং ত্রুটিগুলির দিকে একবার নজর দিন

আপনার পয়েন্টার দেখুন

60 bytes in 1 blocks are definitely lost in loss record 1 of 1
   at 0x4C2BB78: realloc (vg_replace_malloc.c:785)
   by 0x4005E4: resizeArray (main.c:12)
   by 0x40062E: main (main.c:19)

এবং কোড:

#include <stdlib.h>
#include <stdint.h>

struct _List {
    int32_t* data;
    int32_t length;
};
typedef struct _List List;

List* resizeArray(List* array) {
    int32_t* dPtr = array->data;
    dPtr = realloc(dPtr, 15 * sizeof(int32_t)); //doesn't update array->data
    return array;
}

int main() {
    List* array = calloc(1, sizeof(List));
    array->data = calloc(10, sizeof(int32_t));
    array = resizeArray(array);

    free(array->data);
    free(array);
    return 0;
}

শিক্ষক সহকারী হিসাবে, আমি প্রায়ই এই ভুলটি দেখেছি। শিক্ষার্থী একটি স্থানীয় ভেরিয়েবল ব্যবহার করে এবং মূল পয়েন্টারটি আপডেট করতে ভুলে যায়। এখানে ত্রুটিটি লক্ষ্য করছে যা reallocবরাদ্দ হওয়া মেমরিটিকে অন্য কোথাও স্থানান্তর করতে এবং পয়েন্টারের অবস্থান পরিবর্তন করতে পারে। তারপরে অ্যারে কোথায় স্থানান্তরিত হয়েছিল তা resizeArrayনা জানিয়ে আমরা array->dataচলে যাই।

অবৈধ লেখা

1 errors in context 1 of 1:
Invalid write of size 1
   at 0x4005CA: main (main.c:10)
 Address 0x51f905a is 0 bytes after a block of size 26 alloc'd
   at 0x4C2B975: calloc (vg_replace_malloc.c:711)
   by 0x400593: main (main.c:5)

এবং কোড:

#include <stdlib.h>
#include <stdint.h>

int main() {
    char* alphabet = calloc(26, sizeof(char));

    for(uint8_t i = 0; i < 26; i++) {
        *(alphabet + i) = 'A' + i;
    }
    *(alphabet + 26) = '\0'; //null-terminate the string?

    free(alphabet);
    return 0;
}

লক্ষ্য করুন যে ভ্যালগ্রাইন্ড আমাদের উপরের কোডের মন্তব্য করা লাইনের দিকে দেখায়। 26 মাপের অ্যারেটি সূচকযুক্ত [0,25] যার কারণে *(alphabet + 26)একটি অবৈধ লেখা — এটি সীমার বাইরে। একটি অবৈধ লিখন একের পর এক ত্রুটির সাধারণ ফল। আপনার অ্যাসাইনমেন্ট অপারেশনের বাম দিকে দেখুন।

অবৈধ পঠন

1 errors in context 1 of 1:
Invalid read of size 1
   at 0x400602: main (main.c:9)
 Address 0x51f90ba is 0 bytes after a block of size 26 alloc'd
   at 0x4C29BE3: malloc (vg_replace_malloc.c:299)
   by 0x4005E1: main (main.c:6)

এবং কোড:

#include <stdlib.h>
#include <stdint.h>

int main() {
    char* destination = calloc(27, sizeof(char));
    char* source = malloc(26 * sizeof(char));

    for(uint8_t i = 0; i < 27; i++) {
        *(destination + i) = *(source + i); //Look at the last iteration.
    }

    free(destination);
    free(source);
    return 0;
}

ভ্যালগ্রাইন্ড আমাদের উপরের মন্তব্য করা লাইনে নির্দেশ করে। এখানে সর্বশেষ পুনরাবৃত্তি দেখুন, যা
*(destination + 26) = *(source + 26);। যাইহোক, *(source + 26)আবার সীমার বাইরে, একইভাবে অবৈধ লেখার মতো। অবৈধ পাঠগুলিও বাইরের ত্রুটিগুলির একটি সাধারণ ফলাফল। আপনার অ্যাসাইনমেন্ট অপারেশনের ডান দিকটি দেখুন।


ওপেন সোর্স (ইউ / ডাইস) শীর্ষস্থানীয়

আমি কীভাবে জানতে পারি যে যখন ফুটো আমার হয়? আমি যখন অন্য কারও কোড ব্যবহার করছি তখন কীভাবে আমার ফুটোটি পাওয়া যাবে? আমি একটি ফাঁস পেয়েছি যা আমার নয়; আমার কিছু করা উচিত? সবই বৈধ প্রশ্ন। প্রথম, 2 বাস্তব-বিশ্বের উদাহরণ যা 2 টি শ্রেণির সাধারণ মুখোমুখি হয়।

জ্যানসন : একটি জেএসওএন লাইব্রেরি

#include <jansson.h>
#include <stdio.h>

int main() {
    char* string = "{ \"key\": \"value\" }";

    json_error_t error;
    json_t* root = json_loads(string, 0, &error); //obtaining a pointer
    json_t* value = json_object_get(root, "key"); //obtaining a pointer
    printf("\"%s\" is the value field.\n", json_string_value(value)); //use value

    json_decref(value); //Do I free this pointer?
    json_decref(root);  //What about this one? Does the order matter?
    return 0;
}

এটি একটি সাধারণ প্রোগ্রাম: এটি একটি JSON স্ট্রিং পড়ে এবং এটি বিশ্লেষণ করে। তৈরি করার সময় আমরা আমাদের জন্য পার্সিং করতে লাইব্রেরি কল ব্যবহার করি। জ্যানসন প্রয়োজনীয় বরাদ্দগুলি গতিশীলভাবে তৈরি করে যেহেতু জেএসওএন নিজের বাসা বাঁধতে পারে। তবে, এর অর্থ এই নয় যে আমরা decrefবা "ফ্রি" প্রতিটি ফাংশন থেকে আমাদেরকে দেওয়া স্মৃতি। প্রকৃতপক্ষে, এই কোডটি আমি উপরে লিখেছি একটি "অবৈধ পঠন" এবং একটি "অবৈধ লেখা" উভয়ই ছুঁড়ে। আপনি যখন decrefলাইনটি বের করেন তখন এই ত্রুটিগুলি চলে যায় value

কেন? ভেরিয়েবলটিকে valueজ্যানসন এপিআইতে "ধার করা রেফারেন্স" হিসাবে বিবেচনা করা হয়। জ্যানসন আপনার জন্য এটির মেমরির খোঁজ রাখে এবং আপনাকে কেবল decref একে অপরের থেকে আলাদা জেএসওএন কাঠামো রাখতে হয়। এখানে পাঠ: ডকুমেন্টেশন পড়ুন । সত্যিই। এটি কখনও কখনও বুঝতে অসুবিধা হয় তবে এই জিনিসগুলি কেন ঘটে তা তারা আপনাকে জানায়। পরিবর্তে, এই মেমরি ত্রুটি সম্পর্কে আমাদের বিদ্যমান প্রশ্ন রয়েছে

এসডিএল : একটি গ্রাফিক্স এবং গেমিং লাইব্রেরি

#include "SDL2/SDL.h"

int main(int argc, char* argv[]) {
    if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO) != 0) {
        SDL_Log("Unable to initialize SDL: %s", SDL_GetError());
        return 1;
    }

    SDL_Quit();
    return 0;
}

এই কোডটিতে কি সমস্যা আছে ? এটি আমার জন্য ধারাবাহিকভাবে 212 B কিবি মেমরি ফাঁস করে দেয়। এটি সম্পর্কে চিন্তা করতে এক মুহুর্ত সময় নিন। আমরা এসডিএল চালু এবং তারপর বন্ধ। উত্তর? ভুল কিছুই নেই.

এটি প্রথমে উদ্ভট লাগতে পারে । সত্য বলা যেতে পারে, গ্রাফিকগুলি অগোছালো এবং কখনও কখনও আপনাকে স্ট্যান্ডার্ড লাইব্রেরির অংশ হিসাবে কিছু ফাঁস গ্রহণ করতে হয়। এখানে পাঠ: আপনার প্রতিটি মেমরি ফুটো কমাতে হবে না । কখনও কখনও আপনাকে কেবল ফাঁসগুলি দমন করতে হবে কারণ তারা ज्ञিত সমস্যাগুলি যা আপনি কিছুই করতে পারবেন না । (আপনার নিজের ফাঁস উপেক্ষা করার জন্য এটি আমার অনুমতি নয়!)

অকার্যকর উত্তর

আমি কীভাবে জানতে পারি যে যখন ফুটো আমার হয়?
এইটা. (99% নিশ্চিত, যাইহোক)

আমি যখন অন্য কারও কোড ব্যবহার করছি তখন কীভাবে আমার ফুটোটি পাওয়া যাবে?
সম্ভাবনা অন্য কেউ ইতিমধ্যে এটি খুঁজে পেয়েছে। গুগল চেষ্টা করে দেখুন! যদি এটি ব্যর্থ হয় তবে আমি আপনাকে উপরে যে দক্ষতা দিয়েছি তা ব্যবহার করুন। যদি এটি ব্যর্থ হয় এবং আপনি বেশিরভাগ এপিআই কল এবং আপনার নিজের স্ট্যাকের সামান্য কিছু দেখতে পান, পরবর্তী প্রশ্নটি দেখুন।

আমি একটি ফাঁস পেয়েছি যা আমার নয়; আমার কিছু করা উচিত?
হ্যাঁ! বেশিরভাগ এপিআইয়ের কাছে বাগ এবং সমস্যাগুলি প্রতিবেদন করার উপায় রয়েছে। তাদের ব্যাবহার করুন! আপনি আপনার প্রকল্পে যে সরঞ্জামগুলি ব্যবহার করছেন তা ফিরিয়ে দিতে সহায়তা করুন!


আরও পড়া

এই দীর্ঘ আমার সাথে থাকার জন্য ধন্যবাদ। আমি আশা করি আপনি কিছু শিখেছেন, যেমন আমি এই উত্তরটিতে পৌঁছানোর বিস্তৃত লোকদের দিকে ঝোঁক দেওয়ার চেষ্টা করেছি। আমি আশা করি কিছু জিনিস আপনি সেই পথে জিজ্ঞাসা করেছেন: সি এর মেমরি বরাদ্দকারী কীভাবে কাজ করে? মেমরি ফাঁস এবং একটি মেমরি ত্রুটি আসলে কী? সেগফাল্ট থেকে তারা কীভাবে আলাদা? ভালগ্র্যান্ড কীভাবে কাজ করে? আপনার যদি এগুলির কোনও থাকে তবে দয়া করে আপনার কৌতূহলকে খাওয়াবেন:


4
আরও ভাল উত্তর, একটি লজ্জা এটি গৃহীত উত্তর নয়।
এ স্মোলিয়াক

আমি বিশ্বাস করি যে এটি করা একটি ভাল অনুশীলন, আমি নিজেই কয়েকটি করেছি
এ স্মোলিয়াক

1
আমি কি এই উত্তরটি তারকাচিহ্নিত করতে এবং এটি নিজের জন্য ভবিষ্যতের রেফারেন্স হিসাবে ব্যবহার করতে পারি? ভাল কাজ!
জ্যাপ করুন

নেই memcheckটুল ডিফল্টরূপে সক্রিয় করা হয়?
অভিহোরা

হ্যাঁ ম্যান পৃষ্ঠাটি আমাদের জানায় যে memcheckএটি ডিফল্ট সরঞ্জাম:--tool=<toolname> [default: memcheck]
জোশুয়া ডিটওয়েলার

146

এটা চেষ্টা কর:

valgrind --leak-check=full -v ./your_program

যতক্ষণ ভালগ্রাইন্ড ইনস্টল করা থাকে ততক্ষণ এটি আপনার প্রোগ্রামের মধ্য দিয়ে যাবে এবং আপনাকে কী বলছে। এটি আপনাকে পয়েন্টার এবং আনুমানিক জায়গা দিতে পারে যেখানে আপনার ফাঁস পাওয়া যেতে পারে। আপনি যদি সেগফল্ট করছেন তবে এটি চালিয়ে যাওয়ার চেষ্টা করুন gdb


"আপনার_প্রগ্রাম" এর অর্থ কী? এই উত্স কোড অবস্থান বা অ্যাপ্লিকেশন নাম যেমন apk ফাইল?
হোয়াংভিউ

7
your_program== এক্সিকিউটেবল নাম বা আপনার অ্যাপ্লিকেশনটি চালানোর জন্য যে কোনও কমান্ড ব্যবহার করুন।
রাগ


1

আপনি নীচে .bashrc ফাইলে একটি উপন্যাস তৈরি করতে পারেন

alias vg='valgrind --leak-check=full -v --track-origins=yes --log-file=vg_logfile.out'

সুতরাং যখনই আপনি মেমরি ফাঁস পরীক্ষা করতে চান, কেবল সহজভাবে করুন

vg ./<name of your executable> <command line parameters to your executable>

এটি বর্তমান ডিরেক্টরিতে একটি ভালগ্রাইন্ড লগ ফাইল তৈরি করবে।

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