কোন প্রোগ্রামে মেমরি ফাঁস পেতে আমি কীভাবে ভালগ্রাইন্ড ব্যবহার করব?
দয়া করে কেউ আমাকে সহায়তা করুন এবং পদ্ধতিটি সম্পাদনের পদক্ষেপগুলি বর্ণনা করুন?
আমি উবুন্টু 10.04 ব্যবহার করছি এবং আমার একটি প্রোগ্রাম রয়েছে a.c
, দয়া করে আমাকে সাহায্য করুন।
কোন প্রোগ্রামে মেমরি ফাঁস পেতে আমি কীভাবে ভালগ্রাইন্ড ব্যবহার করব?
দয়া করে কেউ আমাকে সহায়তা করুন এবং পদ্ধতিটি সম্পাদনের পদক্ষেপগুলি বর্ণনা করুন?
আমি উবুন্টু 10.04 ব্যবহার করছি এবং আমার একটি প্রোগ্রাম রয়েছে a.c
, দয়া করে আমাকে সাহায্য করুন।
উত্তর:
ওপিকে অপমান করার জন্য নয়, তবে যারা এই প্রশ্নে আসে এবং এখনও লিনাক্সে নতুন তারা আপনাকে আপনার সিস্টেমে ভালগ্রিড ইনস্টল করতে হতে পারে ।
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)
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% নিশ্চিত, যাইহোক)
আমি যখন অন্য কারও কোড ব্যবহার করছি তখন কীভাবে আমার ফুটোটি পাওয়া যাবে?
সম্ভাবনা অন্য কেউ ইতিমধ্যে এটি খুঁজে পেয়েছে। গুগল চেষ্টা করে দেখুন! যদি এটি ব্যর্থ হয় তবে আমি আপনাকে উপরে যে দক্ষতা দিয়েছি তা ব্যবহার করুন। যদি এটি ব্যর্থ হয় এবং আপনি বেশিরভাগ এপিআই কল এবং আপনার নিজের স্ট্যাকের সামান্য কিছু দেখতে পান, পরবর্তী প্রশ্নটি দেখুন।
আমি একটি ফাঁস পেয়েছি যা আমার নয়; আমার কিছু করা উচিত?
হ্যাঁ! বেশিরভাগ এপিআইয়ের কাছে বাগ এবং সমস্যাগুলি প্রতিবেদন করার উপায় রয়েছে। তাদের ব্যাবহার করুন! আপনি আপনার প্রকল্পে যে সরঞ্জামগুলি ব্যবহার করছেন তা ফিরিয়ে দিতে সহায়তা করুন!
এই দীর্ঘ আমার সাথে থাকার জন্য ধন্যবাদ। আমি আশা করি আপনি কিছু শিখেছেন, যেমন আমি এই উত্তরটিতে পৌঁছানোর বিস্তৃত লোকদের দিকে ঝোঁক দেওয়ার চেষ্টা করেছি। আমি আশা করি কিছু জিনিস আপনি সেই পথে জিজ্ঞাসা করেছেন: সি এর মেমরি বরাদ্দকারী কীভাবে কাজ করে? মেমরি ফাঁস এবং একটি মেমরি ত্রুটি আসলে কী? সেগফাল্ট থেকে তারা কীভাবে আলাদা? ভালগ্র্যান্ড কীভাবে কাজ করে? আপনার যদি এগুলির কোনও থাকে তবে দয়া করে আপনার কৌতূহলকে খাওয়াবেন:
memcheck
টুল ডিফল্টরূপে সক্রিয় করা হয়?
memcheck
এটি ডিফল্ট সরঞ্জাম:--tool=<toolname> [default: memcheck]
এটা চেষ্টা কর:
valgrind --leak-check=full -v ./your_program
যতক্ষণ ভালগ্রাইন্ড ইনস্টল করা থাকে ততক্ষণ এটি আপনার প্রোগ্রামের মধ্য দিয়ে যাবে এবং আপনাকে কী বলছে। এটি আপনাকে পয়েন্টার এবং আনুমানিক জায়গা দিতে পারে যেখানে আপনার ফাঁস পাওয়া যেতে পারে। আপনি যদি সেগফল্ট করছেন তবে এটি চালিয়ে যাওয়ার চেষ্টা করুন gdb
।
your_program
== এক্সিকিউটেবল নাম বা আপনার অ্যাপ্লিকেশনটি চালানোর জন্য যে কোনও কমান্ড ব্যবহার করুন।
আপনি চালাতে পারেন:
valgrind --leak-check=full --log-file="logfile.out" -v [your_program(and its arguments)]
আপনি নীচে .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>
এটি বর্তমান ডিরেক্টরিতে একটি ভালগ্রাইন্ড লগ ফাইল তৈরি করবে।