পাইথনে আমি কীভাবে স্পষ্টভাবে মেমরিটি মুক্ত করতে পারি?


387

আমি একটি পাইথন প্রোগ্রাম লিখেছিলাম যা ত্রিভুজগুলি উপস্থাপন করে কয়েক মিলিয়ন অবজেক্ট তৈরি করতে একটি বড় ইনপুট ফাইলে কাজ করে। অ্যালগরিদমটি হ'ল:

  1. একটি ইনপুট ফাইল পড়ুন
  2. ফাইলটি প্রক্রিয়া করুন এবং ত্রিভুজগুলির একটি তালিকা তৈরি করুন, তাদের উল্লম্ব দ্বারা প্রতিনিধিত্ব করুন
  3. শীর্ষ বিন্যাসে শীর্ষেগুলি আউটপুট দিন: ত্রিভুজের একটি তালিকা অনুসরণ করে শীর্ষে অবস্থিত একটি তালিকা। ত্রিভুজগুলি সূক্ষ্ম সূচকে উল্লম্ব তালিকার প্রতিনিধিত্ব করে

বন্ধ করার প্রয়োজনীয়তাটি আমি ত্রিভুজগুলি প্রিন্ট করার আগে উল্লম্বের সম্পূর্ণ তালিকাটি মুদ্রণ করে রাখার অর্থ হল ফাইলগুলিতে আউটপুট লেখার আগে আমাকে স্মৃতিতে ত্রিভুজগুলির তালিকাটি ধারণ করতে হবে। এরই মধ্যে তালিকার মাপের কারণে আমি মেমরির ত্রুটিগুলি পাচ্ছি।

পাইথনকে বলার সর্বোত্তম উপায় কী যে আমার আর কিছু ডেটা দরকার নেই এবং এটি মুক্ত করা যায়?


11
কোনও মধ্যবর্তী ফাইলে ত্রিভুজগুলি কীভাবে মুদ্রণ করবেন না এবং যখন আপনার প্রয়োজন হবে তখন সেগুলি আবার পড়ুন?
অ্যালিস পুরসেল

2
এই প্রশ্নটি প্রায় দুটি ভিন্ন জিনিস হতে পারে। একই পাইথন প্রক্রিয়া থেকে সেই ত্রুটিগুলি কি, সেই ক্ষেত্রে আমরা পাইথন প্রক্রিয়াটির হিপগুলিতে মেমরি মুক্ত করার বিষয়ে চিন্তা করি, বা সেগুলি সিস্টেমের বিভিন্ন প্রক্রিয়া থেকে পাওয়া যায়, সেই ক্ষেত্রে আমরা ওএসে মেমরি মুক্ত করার বিষয়ে চিন্তা করি?
চার্লস ডাফি

উত্তর:


453

পাইথন অফিশিয়াল ডকুমেন্টেশন অনুসারে , আপনি আবর্জনা সংগ্রাহককে সাথে নিরর্থক মেমরি ছেড়ে দিতে বাধ্য করতে পারেন gc.collect()। উদাহরণ:

import gc
gc.collect()

19
বিষয়গুলি কোনও অস্বাভাবিক ক্ষেত্রে বাদে ঘন ঘন আবর্জনা সংগ্রহ করা হয়, তাই আমি মনে করি না এটি বেশি সাহায্য করবে।
লেনার্ট রেজেব্রো

24
সাধারণভাবে, gc.collect () এড়ানো উচিত। আবর্জনা সংগ্রহকারী জানেন কিভাবে এটির কাজটি করা যায়। এটি বলে, ওপি যদি এমন পরিস্থিতিতে থাকে যে হঠাৎ করে তিনি প্রচুর অবজেক্টকে (লক্ষ লক্ষ লোকের মতো) কমিয়ে দিচ্ছেন, তবে gc.collect কার্যকর হতে পারে।
জেসন বেকার

164
প্রকৃতপক্ষে gc.collect()একটি লুপের শেষে নিজেকে কল করা খণ্ড মেমরি এড়াতে সহায়তা করতে পারে যা ফলস্বরূপ কর্মক্ষমতা বজায় রাখতে সহায়তা করে। আমি এটি একটি উল্লেখযোগ্য পার্থক্য করতে দেখেছি (~ 20% রানটাইম আইআইআরসি)
রবএম

38
আমি পাইথন ৩.6 ব্যবহার করছি। gc.collect()এইচডিএফ 5 (500 কে সারি) থেকে পান্ডাস ডেটা ফ্রেম লোড করার পরে কল করা মেমরির ব্যবহার 1.7 গিগাবাইট থেকে 500 এমবি হ্রাস করেছে
জন

15
আমাকে 32 গিগাবাইট মেমরির সাহায্যে একটি সিস্টেমে 25GB এর বেশ কয়েকটি নাম্বার অ্যারে লোড করতে এবং প্রক্রিয়া করা দরকার। ব্যবহার করা del my_arrayদ্বারা অনুসরণ gc.collect()পর অ্যারে প্রক্রিয়াকরণের একমাত্র উপায় মেমরির আসলে মুক্তি হয় এবং আমার প্রক্রিয়া পরবর্তী অ্যারের লোড করতে প্রাণে বেঁচে যান।
ডেভিড

113

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

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

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


31
আমি নিশ্চিত এটির একটি তুচ্ছ উদাহরণ দেখতে চাই।
অ্যারন হল

3
সিরিয়াসলি। @ অ্যারোনহাল যা বলেছে।
নুব সাইবোট

17
@AaronHall তুচ্ছ উদাহরণ এখন উপলব্ধ ব্যবহার multiprocessing.Managerফাইল বদলে ভাগ রাষ্ট্র বাস্তবায়ন।
ব্যবহারকারী 4815162342

48

delবিবৃতি ব্যবহারের হতে পারে, কিন্তু IIRC এটি মেমরি মুক্ত করতে নিশ্চিত করা হয় নাডক্স এখানে আছেন ... এবং কেন এটি মুক্তি হয় না এখানে

আমি শুনেছি লিনাক্স এবং ইউনিক্স-টাইপ সিস্টেমে লোকেরা অজগর প্রক্রিয়াটির জন্য কিছু কাজ করার জন্য চেষ্টা করছে, ফলাফল পেয়েছে এবং তারপরে এটি হত্যা করে।

পাইথন আবর্জনা সংগ্রহকারী সম্পর্কে এই নিবন্ধটিতে নোট রয়েছে, তবে আমি মনে করি মেমরি নিয়ন্ত্রণের অভাব পরিচালিত মেমরির ক্ষতি হয়


আয়রন পাইথন এবং জাইথন ​​এই সমস্যা এড়াতে অন্য বিকল্প হতে পারে?
এস্তেবান কাবার

@ যাত্রী: না, তা হবে না। এবং না অন্য কোন ভাষা, সত্যিই হবে। সমস্যাটি হ'ল তিনি একটি লিস্টে প্রচুর পরিমাণে ডেটা পড়েন এবং মেমরির জন্য ডেটাটি খুব বড়।
লেনার্ট রেজেব্রো

1
এটি আয়রন পাইথন বা জাইথনের অধীনে আরও খারাপ হতে পারে । এই পরিবেশগুলিতে, আপনি গ্যারান্টিযুক্তও নন যে মেমরিটি মুক্তি দেওয়া হবে যদি অন্য কোনও কিছু রেফারেন্স না রাখে।
জেসন বেকার

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

32

পাইথন আবর্জনা-সংগৃহীত, সুতরাং আপনি যদি আপনার তালিকার আকার হ্রাস করেন তবে এটি মেমোরিটিকে পুনরায় দাবি করবে। ভেরিয়েবল সম্পূর্ণরূপে মুক্তি পেতে আপনি "ডেল" বিবৃতিটি ব্যবহার করতে পারেন:

biglist = [blah,blah,blah]
#...
del biglist

18
এটি সত্য এবং সত্য নয়। তালিকার আকার হ্রাস করার সময় মেমরিটিকে পুনরুদ্ধার করতে দেয় তবে কখন এটি ঘটবে তার কোনও গ্যারান্টি নেই।
ব্যবহারকারী 142350

3
না, তবে সাধারণত এটি সাহায্য করবে। যাইহোক, আমি এখানে প্রশ্নটি বুঝতে পেরেছি, সমস্যাটি হ'ল তার এতগুলি অবজেক্ট থাকতে হবে যে সে সমস্তগুলি প্রক্রিয়া করার আগে স্মৃতি থেকে বেরিয়ে যায়, যদি সে সেগুলি তালিকায় পড়ে তবে reads তিনি প্রক্রিয়াজাত হওয়ার আগে তালিকাটি মুছে ফেলা কোনও কার্যকর সমাধান হওয়ার সম্ভাবনা নেই। ;)
লেনার্ট রেজেব্রো

3
একটি স্বল্প-স্মৃতি / স্মৃতি ছাড়িয়ে যাওয়া অবস্থা আবর্জনা সংগ্রাহকের "জরুরি অবস্থা" চালিয়ে দেবে না?
জেরেমি ফ্রাইজনার

4
বিগলিস্ট = [] মেমরি ছেড়ে দেবে?
নিউউইগুর

3
হ্যাঁ, যদি পুরানো তালিকাটি অন্য কোনও কিছু দ্বারা রেফারেন্স না হয়।
নেড ব্যাচেল্ডার

22

আপনি স্পষ্টভাবে মেমরি মুক্ত করতে পারবেন না। আপনার যা করা দরকার তা হ'ল আপনি অবজেক্টের রেফারেন্স রাখবেন না তা নিশ্চিত করা। তারপরে এগুলি মেমরি মুক্ত করে ময়লা ফেলা হবে।

আপনার ক্ষেত্রে, যখন আপনার বড় তালিকাগুলি প্রয়োজন হয়, আপনার সাধারণত কোডটি পুনর্গঠন করা দরকার, সাধারণত পরিবর্তে জেনারেটর / পুনরুক্তি ব্যবহার করে। এইভাবে আপনার মেমরির মোটেও বড় তালিকা থাকা দরকার নেই।

http://www.prasannatech.net/2009/07/introduction-python-generators.html


1
যদি এই পদ্ধতির সম্ভাব্য হয়, তবে সম্ভবত এটি করা ভাল। তবে এটি লক্ষ করা উচিত যে আপনি পুনরাবৃত্তকারীগুলিতে এলোমেলো অ্যাক্সেস করতে পারবেন না, যা সমস্যার কারণ হতে পারে।
জেসন বেকার

এটি সত্য, এবং যদি এটি প্রয়োজনীয় হয়, তবে এলোমেলোভাবে বড় ডেটা ডেটাসেটগুলি অ্যাক্সেস করতে কোনও ধরণের ডাটাবেসের প্রয়োজন হতে পারে।
লেনার্ট রেজেব্রো 22:22

আপনি অন্য পুনরুক্তকারীর এলোমেলো উপসেটটি বের করতে সহজেই একটি পুনরায় ব্যবহার করতে পারেন।
এস .লট

সত্য, তবে তারপরে আপনাকে সাবসেটটি পাওয়ার জন্য সমস্ত কিছুর পুনরাবৃত্তি করতে হবে, যা খুব ধীর হবে।
লেনার্ট রেজেব্রো

21

( delআপনার বন্ধু হতে পারে, কারণ এটি কোনও বস্তুগুলিকে ডিলেটযোগ্য হিসাবে চিহ্নিত করে যখন তাদের সাথে অন্য কোনও উল্লেখ নেই Now এখন, প্রায়শই সিপথন ইন্টারপ্রেটার এই স্মৃতিটি পরবর্তী ব্যবহারের জন্য রাখে, যাতে আপনার অপারেটিং সিস্টেমটি সম্ভবত "মুক্ত" স্মৃতি দেখতে না পারে))

আপনার ডেটার জন্য আরও কমপ্যাক্ট কাঠামো ব্যবহার করে আপনি প্রথমে কোনও মেমরির সমস্যায় পড়বেন না। সুতরাং, স্ট্যান্ডার্ড arrayমডিউল বা তৃতীয় পক্ষের numpyমডিউল দ্বারা ব্যবহৃত বিন্যাসের চেয়ে সংখ্যাগুলির তালিকা মেমরি-দক্ষ অনেক কম । আপনি একটি NumPy 3xN অ্যারে এবং আপনার ত্রিভুজগুলি একটি N-উপাদান অ্যারেতে রেখে আপনার স্মৃতি সংরক্ষণ করবেন memory


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

আমি দেখছি আপনি কোথা থেকে এসেছেন: আমি সেই অনুযায়ী উত্তর আপডেট করব। আমি বুঝতে পারি যে সিপিথন ইন্টারপ্রেটার আসলে কিছু মধ্যবর্তী পদ্ধতিতে কাজ করে: delপাইথনের দৃষ্টিকোণ থেকে স্মৃতিটিকে মুক্ত করে, তবে সাধারণত সি রানটাইম লাইব্রেরির বা ওএসের দৃষ্টিকোণ থেকে নয়। তথ্যসূত্র: stackoverflow.com/a/32167625/4297 , effbot.org/pyfaq/...
এরিক হে লেবিগোট

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

11

একটি ফাইল থেকে গ্রাফ পড়তে আমার একই সমস্যা ছিল। প্রক্রিয়াকরণটিতে 200,000x200 000 ফ্লোট ম্যাট্রিক্স (একবারে এক লাইন) মেমরির সাথে খাপ খায় না এমন গণনা অন্তর্ভুক্ত ছিল। gc.collect()সমস্যাটির স্মৃতি-সম্পর্কিত দিকটি স্থির করে কম্পিউটেশনের মধ্যে মেমরি মুক্ত করার চেষ্টা করা হয়েছিল তবে এর ফলে কর্মক্ষমতা সংক্রান্ত সমস্যা দেখা দিয়েছে: কেন জানি না তবে যদিও ব্যবহৃত মেমরির পরিমাণ স্থির ছিল, প্রতিটি নতুন কল থেকে gc.collect()আরও কিছুটা সময় নিয়েছিল আগেরটি এত তাড়াতাড়ি আবর্জনা সংগ্রহ করা বেশিরভাগ গণনার সময় নিয়েছিল।

মেমরি এবং পারফরম্যান্স উভয় সমস্যার সমাধান করার জন্য আমি কোথাও একবার পড়েছি এমন মাল্টিথ্রেডিং ট্রিকটি ব্যবহার করতে শুরু করেছি (দুঃখিত, আমি সম্পর্কিত পোস্টটি আর খুঁজে পাচ্ছি না)। আমি ফাইলের প্রতিটি লাইন একটি বড় forলুপে পড়ার আগে , এটি প্রক্রিয়াজাতকরণ gc.collect()এবং মেমরির জায়গা মুক্ত করার জন্য একবার এবং একবার চালাচ্ছিলাম । এখন আমি একটি ফাংশন বলি যা একটি নতুন থ্রেডে ফাইলের একটি অংশ পড়ে এবং প্রক্রিয়া করে। থ্রেডটি শেষ হয়ে গেলে অদ্ভুত পারফরম্যান্স সমস্যা ছাড়াই মেমরিটি স্বয়ংক্রিয়ভাবে মুক্ত হয় is

ব্যবহারিকভাবে এটি এর মতো কাজ করে:

from dask import delayed  # this module wraps the multithreading
def f(storage, index, chunk_size):  # the processing function
    # read the chunk of size chunk_size starting at index in the file
    # process it using data in storage if needed
    # append data needed for further computations  to storage 
    return storage

partial_result = delayed([])  # put into the delayed() the constructor for your data structure
# I personally use "delayed(nx.Graph())" since I am creating a networkx Graph
chunk_size = 100  # ideally you want this as big as possible while still enabling the computations to fit in memory
for index in range(0, len(file), chunk_size):
    # we indicates to dask that we will want to apply f to the parameters partial_result, index, chunk_size
    partial_result = delayed(f)(partial_result, index, chunk_size)

    # no computations are done yet !
    # dask will spawn a thread to run f(partial_result, index, chunk_size) once we call partial_result.compute()
    # passing the previous "partial_result" variable in the parameters assures a chunk will only be processed after the previous one is done
    # it also allows you to use the results of the processing of the previous chunks in the file if needed

# this launches all the computations
result = partial_result.compute()

# one thread is spawned for each "delayed" one at a time to compute its result
# dask then closes the tread, which solves the memory freeing issue
# the strange performance issue with gc.collect() is also avoided

1
আমি ভাবছি আপনি কেন মন্তব্যের জন্য পাইথনে # এর পরিবর্তে `//` `using ব্যবহার করছেন।
জে.সি. রোকমন্ডে

আমি ভাষার মধ্যে মিশে গিয়েছিলাম। মন্তব্যের জন্য আপনাকে ধন্যবাদ, আমি সিনট্যাক্স আপডেট করেছি।
রেটজড

9

অন্যরা কিছু উপায়ে পোস্ট করেছেন যাতে আপনি স্মৃতি মুক্ত করার জন্য পাইথন দোভাষীকে "কোক্স" করতে সক্ষম হতে পারেন (বা অন্যথায় স্মৃতি সমস্যা হতে পারে না)। সম্ভাবনা হ'ল প্রথমে আপনার ধারণাটি চেষ্টা করা উচিত। তবে আমি আপনাকে আপনার প্রশ্নের সরাসরি উত্তর দেওয়া জরুরী মনে করি।

পাইথনকে সরাসরি মেমরি ফ্রি করার কোনও উপায় নেই। বিষয়টির সত্যতা হ'ল আপনি যদি এই নিম্ন স্তরের নিয়ন্ত্রণ চান তবে আপনাকে সি বা সি ++ তে একটি এক্সটেনশন লিখতে হবে।

এটি বলেছিল, এর সাথে সাহায্য করার জন্য কিছু সরঞ্জাম রয়েছে:


3
gc.collect () এবং del gc.garbage [:] যখন আমি প্রচুর পরিমাণে স্মৃতি ব্যবহার করি তখন ঠিকঠাক কাজ করুন
অ্যান্ড্রু স্কট ইভানস

3

আপনি যদি ভার্টেক্স পুনঃব্যবহারের বিষয়ে যত্ন না রাখেন তবে আপনার দুটি আউটপুট ফাইল থাকতে পারে - একটি শীর্ষে এবং ত্রিভুজগুলির জন্য। তারপরে ত্রিভুজ ফাইলটি ভার্টেক্স ফাইলটিতে যুক্ত করুন you


1
আমি অনুমান করি যে আমি কেবল স্মৃতিতে শীর্ষে রাখতে পারি এবং ত্রিভুজগুলি একটি ফাইলের মধ্যে মুদ্রণ করতে পারি এবং তারপরে কেবল শেষে শীর্ষে প্রিন্ট আউট করতে পারি। তবে কোনও ফাইলকে ত্রিভুজগুলি লেখার কাজটি একটি বিশাল পারফরম্যান্স ড্রেন। সেখানে গতি বাড়াতে কোন উপায় আছে কি যে আপ করবেন?
23:25 '
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.