পাইথনে স্মৃতি প্রকাশ করছে


128

নিম্নলিখিত উদাহরণে মেমরির ব্যবহার সম্পর্কে আমার কয়েকটি সম্পর্কিত প্রশ্ন রয়েছে।

  1. আমি যদি দোভাষী দৌড়ে যাই,

    foo = ['bar' for _ in xrange(10000000)]

    আমার মেশিনে ব্যবহৃত আসল স্মৃতি উঠে যায় 80.9mb। তখন আমি,

    del foo

    রিয়েল মেমরি যায় নিচে, কিন্তু শুধুমাত্র থেকে 30.4mb4.4mbদোভাষা বেসলাইন ব্যবহার করে তাই 26mbওএসে মেমরি প্রকাশ না করার সুবিধা কী ? আপনি কি এত বেশি স্মৃতি আবার ব্যবহার করতে পারেন ভেবে পাইথন "এগিয়ে যাওয়ার পরিকল্পনা" করছে বলে?

  2. কেন এটি 50.5mbবিশেষত প্রকাশ হয় - এর পরিমাণের ভিত্তিতে প্রকাশিত পরিমাণটি কী?

  3. পাইথনকে সমস্ত ব্যবহৃত মেমরি প্রকাশ করতে বাধ্য করার কোনও উপায় আছে (যদি আপনি জানেন যে আপনি আবার এত বেশি স্মৃতি ব্যবহার করবেন না)?

দ্রষ্টব্য এই প্রশ্নটি থেকে পৃথক কীভাবে আমি পাইথনে স্পষ্টভাবে মেমরি মুক্ত করতে পারি? কারণ এই প্রশ্নটি মূলত ডেস্কটপটি আবর্জনা সংগ্রহের মাধ্যমে অবজেক্টগুলি মুক্ত করার পরেও (ব্যবহার gc.collectবা না ব্যবহারের মাধ্যমে ) বেসলাইন থেকে মেমরির ব্যবহার বৃদ্ধির সাথে জড়িত ।


4
এটি লক্ষণীয় যে এই আচরণটি পাইথনের সাথে নির্দিষ্ট নয়। এটি সাধারণত এমন হয় যে যখন কোনও প্রক্রিয়া কিছু গাদা-বরাদ্দ মেমরি মুক্ত করে, প্রক্রিয়াটি মারা না যাওয়া অবধি স্মৃতি ওএসের কাছে ফিরে আসে না।
এনপিই

আপনার প্রশ্নটি একাধিক জিনিস জিজ্ঞাসা করে - এর মধ্যে কয়েকটি ডুপস, যার মধ্যে কিছু এসওর জন্য অনুপযুক্ত, যার মধ্যে কয়েকটি ভাল প্রশ্ন হতে পারে। আপনি কি জিজ্ঞাসা করছেন পাইথন মেমরিটি প্রকাশ করে না, সঠিক পরিস্থিতিতে এটি কীভাবে / করতে পারে না, অন্তর্নিহিত প্রক্রিয়াটি কী, কেন এটি সেভাবে ডিজাইন করা হয়েছিল, সেখানে কোনও কর্মক্ষেত্র রয়েছে বা অন্য কোনও কিছু আছে কিনা?
অবতারিত

2
@ বার্নার্ট আমি অনুরূপ সাবক্লিকেশনগুলিকে একত্রিত করেছি। আপনার প্রশ্নের জবাব দেওয়ার জন্য: আমি জানি পাইথন ওএসকে কিছু মেমরি প্রকাশ করে তবে কেন এটি সব নয় এবং কেন এটি পরিমাণে হয়। যদি এমন পরিস্থিতিতে থাকে যেখানে এটি না পারে তবে কেন? পাশাপাশি workaround।
জ্যারেড


@jww আমি এটি মনে করি না। এই প্রশ্নটি সত্যিই সম্পর্কিত যা কেন ডেলিভারি দিয়ে পুরোপুরি আবর্জনা সংগ্রহের পরেও দোভাষী প্রক্রিয়া কখনই মেমরি প্রকাশ করেনি gc.collect
জেরেড

উত্তর:


86

গাদা উপর বরাদ্দ মেমরি উচ্চ জল চিহ্ন সাপেক্ষে হতে পারে। পাইথনের অভ্যন্তরীণ অপ্টিমাইজেশন দ্বারা জটিল PyObject_Malloc4 টি কিবি পুলগুলিতে ( )) বরাদ্দকরণের মাপের জন্য 8 বাইটের গুণিত - 256 বাইট (3.3-তে 512 বাইট) পর্যন্ত পুলগুলি নিজেরাই 256 কিবি অঙ্গনে রয়েছে, সুতরাং যদি একটি পুলে কেবল একটি ব্লক ব্যবহার করা হয় তবে পুরো 256 কিবি অঙ্গনটি প্রকাশিত হবে না। পাইথন ৩.৩-তে ছোট বস্তু বরাদ্দকারীকে গাদাের পরিবর্তে বেনামে মেমরি মানচিত্র ব্যবহার করতে স্যুইচ করা হয়েছিল, সুতরাং স্মৃতি ছেড়ে দেওয়ার ক্ষেত্রে এটি আরও ভাল সম্পাদন করা উচিত।

অতিরিক্তভাবে, অন্তর্নির্মিত প্রকারগুলি পূর্ববর্তী বরাদ্দ হওয়া সামগ্রীর ফ্রিলিস্টগুলি বজায় রাখে যা ছোট অবজেক্ট বরাদ্দকারীকে ব্যবহার করতে পারে বা নাও পারে। intটাইপ নিজস্ব বরাদ্দ মেমরির সাথে একটি freelist বজায় রাখে, এবং এটি ক্লিয়ারিং কলিং প্রয়োজন PyInt_ClearFreeList()। একে পরিপূর্ণভাবে করে অপ্রত্যক্ষভাবে বলা যেতে পারে gc.collect

এটির মতো চেষ্টা করে দেখুন এবং কী পান তা আমাকে বলুন। এখানে psutil.Process.memory_info এর লিঙ্কটি ।

import os
import gc
import psutil

proc = psutil.Process(os.getpid())
gc.collect()
mem0 = proc.get_memory_info().rss

# create approx. 10**7 int objects and pointers
foo = ['abc' for x in range(10**7)]
mem1 = proc.get_memory_info().rss

# unreference, including x == 9999999
del foo, x
mem2 = proc.get_memory_info().rss

# collect() calls PyInt_ClearFreeList()
# or use ctypes: pythonapi.PyInt_ClearFreeList()
gc.collect()
mem3 = proc.get_memory_info().rss

pd = lambda x2, x1: 100.0 * (x2 - x1) / mem0
print "Allocation: %0.2f%%" % pd(mem1, mem0)
print "Unreference: %0.2f%%" % pd(mem2, mem1)
print "Collect: %0.2f%%" % pd(mem3, mem2)
print "Overall: %0.2f%%" % pd(mem3, mem0)

আউটপুট:

Allocation: 3034.36%
Unreference: -752.39%
Collect: -2279.74%
Overall: 2.23%

সম্পাদনা:

আমি সিস্টেমের অন্যান্য প্রক্রিয়াগুলির প্রভাবগুলি অপসারণ করতে ভিএম আকারের প্রসেসের তুলনায় পরিমাপ করতে চলেছি।

সি রানটাইম (যেমন গ্লিবসি, এমএসভিসিআরটি) শীর্ষে স্থিতিশীল মুক্ত স্থানটি একটি ধ্রুবক, গতিশীল বা কনফিগারযোগ্য থ্রেশহোল্ডে পৌঁছালে হিপ সঙ্কুচিত হয়। malloptগ্লিবিসি দিয়ে আপনি এটির সাথে টিউন করতে পারেন (M_TRIM_THRESHOLD)। এটি দেওয়া, আপনি যে ব্লকটির চেয়ে আরও বেশি - এমনকি আরও অনেক কিছু কমিয়ে দিলে অবাক হওয়ার কিছু নেই free

3.x এ rangeকোনও তালিকা তৈরি করে না, সুতরাং উপরের পরীক্ষাটি 10 ​​মিলিয়ন intঅবজেক্ট তৈরি করবে না । এমনকি যদি এটি intহয় তবে 3.x টাইপটি মূলত একটি 2.x long, যা কোনও ফ্রিলিস্ট প্রয়োগ করে না।


এর memory_info()পরিবর্তে ব্যবহার করুন get_memory_info()এবং xসংজ্ঞায়িত করা হয়েছে
আজিজ আল্টো

intপাইথন 3 তে আপনি 10 ^ 7 গুলি পান তবে প্রতিটি লুপ ভেরিয়েবলের শেষটিকে প্রতিস্থাপন করে যাতে সেগুলি একবারে
ডেভিস হেরিং

আমি একটি মেমরি ফুটো সমস্যার মুখোমুখি হয়েছি এবং আপনি এখানে কী উত্তর দিয়েছেন তার কারণটি অনুমান করি। তবে কীভাবে আমি আমার অনুমান প্রমাণ করতে পারি? এমন কোনও সরঞ্জাম আছে যা দেখায় যে অনেক পুল মলযুক্ত, তবে কেবল একটি ছোট ব্লক ব্যবহার করা হয়েছে?
ruiruige1991

130

আপনি যে প্রশ্নটি এখানে সত্যই যত্নবান তা আমি অনুমান করছি:

পাইথনকে সমস্ত ব্যবহৃত মেমরি প্রকাশ করতে বাধ্য করার কোনও উপায় আছে (যদি আপনি জানেন যে আপনি আবার এত বেশি স্মৃতি ব্যবহার করবেন না)?

কোন নেই. তবে একটি সহজ উপায় আছে: শিশু প্রক্রিয়া।

আপনার যদি 5 মিনিটের জন্য 500MB অস্থায়ী স্টোরেজ প্রয়োজন হয় তবে এর পরে আপনাকে আরও 2 ঘন্টা চালানো দরকার এবং এতো বেশি স্মৃতি আর স্পর্শ করতে পারবেন না, স্মৃতি-নিবিড় কাজটি করার জন্য একটি শিশু প্রক্রিয়া তৈরি করে। যখন শিশু প্রক্রিয়া চলে যায়, স্মৃতিটি মুক্তি পায়।

এটি সম্পূর্ণ তুচ্ছ এবং নিখরচায় নয়, তবে এটি বেশ সহজ এবং সস্তা, যা সাধারণত ব্যবসায়ের পক্ষে সার্থক হওয়ার পক্ষে যথেষ্ট ভাল।

প্রথমত, শিশু প্রক্রিয়া তৈরির সবচেয়ে সহজ উপায়টি হ'ল concurrent.futures(বা, ৩.১ এবং এর আগে futuresপিপিআইতে ব্যাকপোর্ট):

with concurrent.futures.ProcessPoolExecutor(max_workers=1) as executor:
    result = executor.submit(func, *args, **kwargs).result()

আপনার যদি আরও কিছু নিয়ন্ত্রণ প্রয়োজন হয় তবে multiprocessingমডিউলটি ব্যবহার করুন ।

ব্যয়গুলি হ'ল:

  • প্রসেস স্টার্টআপ কিছু প্ল্যাটফর্মগুলিতে ধীরে ধীরে ধীরে ধীরে উইন্ডোজ is আমরা এখানে মিনিসেকেন্ডের কথা বলছি, মিনিট নয়, এবং যদি আপনি 300 সেকেন্ডের মূল্যবান কাজের জন্য একটি শিশুকে ঘুরছেন, আপনি এটি লক্ষ্য করবেন না। তবে এটি নিখরচায় নয়।
  • আপনি যদি ব্যবহার করেন এমন অস্থায়ী মেমরির পরিমাণ যদি সত্যিই বড় হয় তবে এটি করার ফলে আপনার মূল প্রোগ্রামটি সরে যেতে পারে। অবশ্যই আপনি দীর্ঘমেয়াদে সময় সাশ্রয় করছেন, কারণ যদি সেই স্মৃতি চিরতরে ঘুরে বেড়ায় তবে এটি কোনও পর্যায়ে অদলবদল করতে হবে। তবে এটি কিছু ব্যবহারের ক্ষেত্রে ধীরে ধীরে অলসতা খুব লক্ষণীয় হিসাবে একবারে (এবং প্রথম দিকে) বিলম্বিত করতে পারে।
  • প্রক্রিয়াগুলির মধ্যে প্রচুর পরিমাণে ডেটা প্রেরণ করা ধীর হতে পারে। আবার, যদি আপনি 2K এর বেশি যুক্তি প্রেরণের এবং 64K ফলাফল ফিরে পাওয়ার কথা বলছেন তবে আপনি এটি নজরেও দেখবেন না, তবে আপনি যদি প্রচুর পরিমাণে ডেটা প্রেরণ ও গ্রহণ করছেন তবে আপনি অন্য কিছু প্রক্রিয়া ব্যবহার করতে চাইবেন (একটি ফাইল, mmapপ্যাড বা অন্যথায়; এর মধ্যে ভাগ করা মেমরি এপিআই multiprocessing; ইত্যাদি)।
  • প্রক্রিয়াগুলির মধ্যে প্রচুর পরিমাণে ডেটা প্রেরণের অর্থ হ'ল ডেটা বাছাইযোগ্য হতে হয় (বা আপনি যদি তাদের কোনও ফাইল বা ভাগ করে নেওয়া মেমোরিতে আটকে থাকেন, struct-যোগ্য বা আদর্শভাবে ctypesসক্ষম)।

সমস্যাটি সমাধান না
করেও

32

এরিকসুন প্রশ্নের উত্তর # 1 দিয়েছেন, এবং আমি # 3 প্রশ্নের উত্তর দিয়েছি (আসল # 4), তবে এখন আসুন প্রশ্নের উত্তর # 2:

এটি কেন বিশেষত 50.5mb প্রকাশ করে - এর ভিত্তিতে প্রকাশিত পরিমাণটি কী?

এটি কী ভিত্তিতে ভিত্তি করে তা হ'ল, পাইথনের অভ্যন্তরে একটি সম্পূর্ণ সিরিজ এবং mallocএটি পূর্বাভাস দেওয়া খুব কঠিন।

প্রথমত, আপনি কীভাবে মেমরি পরিমাপ করছেন তার উপর নির্ভর করে আপনি কেবল মেমরিতে ম্যাপ করা পৃষ্ঠাগুলি পরিমাপ করতে পারেন। সেক্ষেত্রে যে কোনও সময় পেজারের দ্বারা কোনও পৃষ্ঠা মুছে ফেলা হলে, স্মৃতিটি "মুক্ত" হিসাবে প্রদর্শিত হবে, যদিও তা মুক্ত হয়নি।

অথবা আপনি ব্যবহারযোগ্য পৃষ্ঠাগুলি পরিমাপ করছেন, যা বরাদ্দকৃত-তবে-কখনও-স্পর্শ হওয়া পৃষ্ঠাগুলি (লিনাক্সের মতো আশাবাদীভাবে অতিরিক্ত বরাদ্দ হওয়া সিস্টেমগুলিতে), বরাদ্দ করা হলেও ট্যাগ হওয়া পৃষ্ঠা MADV_FREEইত্যাদি গণনা করতে পারে বা নাও পারে etc.

যদি আপনি সত্যিকার অর্থে বরাদ্দকৃত পৃষ্ঠাগুলি পরিমাপ করে থাকেন (যা আসলে করা খুব দরকারী জিনিস নয় তবে এটি যা আপনি জিজ্ঞাসা করছেন তা মনে হয়), এবং পৃষ্ঠাগুলি সত্যই নির্মূল করা হয়েছে, এটি দুটি ঘটনায় ঘটতে পারে: হয় আপনি " ব্যবহৃত ve brkবা সমমানের তথ্য সেগমেন্ট (খুব বিরল আজকাল) সঙ্কুচিত, অথবা আপনি ব্যবহার করেছি munmapবা অনুরূপ একটি ম্যাপ সেগমেন্ট মুক্তি। (তাত্ত্বিকভাবে পরেরটির একটি ছোটখাটো রূপও রয়েছে, এতে ম্যাপযুক্ত বিভাগের অংশ প্রকাশ করার উপায় রয়েছে যেমন you যেমনটি আপনি অবিলম্বে আনম্যাপ করে এমন MAP_FIXEDএকটি MADV_FREEবিভাগের জন্য এটি চুরি করুন ))

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

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

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

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

আপনি যদি না বস্তুর সঞ্চয়ের একটি ব্লক ডি-এলোকেট জানতে এই একটি কারণ কিনা freeকল, আপনি PyMem বরাদ্দকরণ অভ্যন্তরীণ স্থিতি জানতে, পাশাপাশি তা কিভাবে কার্যকর হচ্ছে হিসাবে আছে। (আবার, আপনাকে কোনও mallocএড অঞ্চলে সর্বশেষ ব্যবহারের ব্লকটি বাতিল করতে হবে, এবং তারপরেও এটি নাও হতে পারে))

আপনি যদি না free একটি mallocইডি অঞ্চল, জানতে এই একটি কারণ কিনা munmapবা সমমানের (অথবা brk), আপনি অভ্যন্তরীণ স্থিতি জানা আছে mallocযে, তা কিভাবে বাস্তবায়ন হচ্ছে সেইসাথে। এবং এটি অন্যদের থেকে পৃথক, অত্যন্ত প্ল্যাটফর্ম-নির্দিষ্ট। (এবং আবারও, আপনাকে সাধারণত mallocকোনও mmapবিভাগের মধ্যে শেষের ব্যবহারকে কমিয়ে আনতে হবে এবং তারপরেও এটি নাও হতে পারে))

সুতরাং, যদি আপনি বুঝতে চান যে কেন এটি ঠিক ৫০.৫ মিমি প্রকাশের কারণে ঘটেছিল, আপনাকে নীচের দিক থেকে এটি সন্ধান করতে চলেছেন। mallocআপনি যখন এই এক বা একাধিক freeকল করেছেন (সম্ভবত 50.5mb এর চেয়ে কিছুটা বেশি) তখন কেন 50.5mb মূল্যমানের পৃষ্ঠা আনম্যাপ করবেন? আপনাকে আপনার প্ল্যাটফর্মটি পড়তে হবে mallocএবং তার বর্তমান অবস্থা দেখতে বিভিন্ন টেবিল এবং তালিকাগুলি হাঁটাতে হবে। (কিছু প্ল্যাটফর্মে, এটি এমনকি সিস্টেম-স্তরের তথ্যও ব্যবহার করতে পারে, যা অফলাইনে পরিদর্শন করার জন্য সিস্টেমের স্ন্যাপশট তৈরি না করে ক্যাপচার করা বেশ অসম্ভব, তবে ভাগ্যক্রমে এটি সাধারণত কোনও সমস্যা নয়)) এবং তারপরে আপনাকে হতে হবে তার উপরে 3 স্তরে একই জিনিস করুন।

সুতরাং, প্রশ্নের একমাত্র দরকারী উত্তর "কারণ"।

আপনি যদি রিসোর্স-সীমাবদ্ধ (যেমন, এম্বেডেড) বিকাশ না করে থাকেন তবে আপনার এই বিবরণগুলির যত্ন নেওয়ার কোনও কারণ নেই।

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


2

প্রথমত, আপনি ঝলক ইনস্টল করতে চাইতে পারেন:

sudo apt-get install python-pip build-essential python-dev lm-sensors 
sudo pip install psutil logutils bottle batinfo https://bitbucket.org/gleb_zhulik/py3sensors/get/tip.tar.gz zeroconf netifaces pymdstat influxdb elasticsearch potsdb statsd pystache docker-py pysnmp pika py-cpuinfo bernhard
sudo pip install glances

তারপরে টার্মিনালে চালাও!

glances

আপনার পাইথন কোডে, ফাইলটির শুরুতে নিম্নলিখিতটি যুক্ত করুন:

import os
import gc # Garbage Collector

"বিগ" পরিবর্তনশীল (উদাহরণস্বরূপ: মাইবিগবার) ব্যবহার করার পরে, আপনি মেমরিটি প্রকাশ করতে চান, আপনার অজগর কোডটিতে নিম্নলিখিতটি লিখুন:

del myBigVar
gc.collect()

অন্য টার্মিনালে, আপনার অজগর কোডটি চালান এবং "গ্লানসস" টার্মিনালে পর্যালোচনা করুন, কীভাবে আপনার সিস্টেমে মেমরিটি পরিচালিত হয়!

শুভকামনা!

পিএস আমি ধরে নিচ্ছি আপনি কোনও ডেবিয়ান বা উবুন্টু সিস্টেমে কাজ করছেন

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