জাভাস্ক্রিপ্টে আবর্জনা সংগ্রাহকের ক্রিয়াকলাপ হ্রাস করার সর্বোত্তম অনুশীলন


96

আমার কাছে মোটামুটি জটিল জাভাস্ক্রিপ্ট অ্যাপ্লিকেশন রয়েছে, যার একটি প্রধান লুপ রয়েছে যা প্রতি সেকেন্ডে 60 বার বলা হয়। মনে হচ্ছে প্রচুর আবর্জনা সংগ্রহ চলছে (ক্রোম দেব সরঞ্জামগুলিতে মেমরির টাইমলাইন থেকে 'স্যাটুথ' আউটপুট ভিত্তিক) - এবং এটি প্রায়শই অ্যাপ্লিকেশনটির কার্যকারিতা প্রভাবিত করে।

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

জন রেসিগের সাধারণ জাভাস্ক্রিপ্ট উত্তরাধিকারের পংক্তিতে অ্যাপটি 'শ্রেণি' তে কাঠামোযুক্ত ।

আমি মনে করি একটি সমস্যা হ'ল কিছু ফাংশনকে প্রতি সেকেন্ডে হাজার বার বলা যেতে পারে (যেহেতু তারা প্রতিটি লুপের পুনরাবৃত্তির সময় কয়েকবার ব্যবহৃত হয়), এবং সম্ভবত এই ফাংশনগুলিতে স্থানীয় স্ট্রিং ভেরিয়েবলগুলি (স্ট্রিং, অ্যারে ইত্যাদি) সমস্যা হতে পারে।

আমি বৃহত্তর / ভারী জিনিসগুলির জন্য অবজেক্ট পুলিং সম্পর্কে সচেতন (এবং আমরা এটি একটি ডিগ্রি পর্যন্ত ব্যবহার করি) তবে আমি বোর্ডের মাধ্যমে প্রয়োগ করা যেতে পারে এমন কৌশলগুলি সন্ধান করছি, বিশেষত টান লুপগুলিতে অনেক বার ডাকা যাওয়া ফাংশন সম্পর্কিত ting ।

আবর্জনা সংগ্রহকারীকে অবশ্যই কাজের পরিমাণ হ্রাস করতে আমি কী কৌশল ব্যবহার করতে পারি?

এবং সম্ভবত এটিও - কোন জিনিসগুলি সবচেয়ে বেশি আবর্জনা সংগ্রহ করা হচ্ছে তা চিহ্নিত করার জন্য কোন কৌশল ব্যবহার করা যেতে পারে? (এটি একটি বহুল পরিমাণে কোডবেস, সুতরাং স্তূপের স্ন্যাপশটের তুলনা করা খুব ফলপ্রসূ হয়নি)


4
আপনার কোডের উদাহরণ রয়েছে যা আপনি আমাদের প্রদর্শন করতে পারেন? তখন প্রশ্নের উত্তর দেওয়া আরও সহজ হবে (তবে সম্ভাব্যও কম সাধারণ, সুতরাং আমি এখানে নিশ্চিত নই)
জন ডিভোরাক

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

4
@ ট্রাভিজেজে: তিনি এটি প্রতি সেকেন্ডে মাত্র 60 বার চালান, এটি একটি সাধারণ অ্যানিমেশন হার। তিনি কম কাজ করতে বলেন না, তবে কীভাবে এটি আরও জঞ্জাল-সংগ্রহ-দক্ষ করবেন।
বার্গি

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

4
@ ট্রাভিসজে - গেম ফ্রেমওয়ার্কে এটি মোটেও অস্বাভাবিক নয়।
আপক্রিক

উত্তর:


131

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

আধুনিক দোভাষীগুলিতে বিভিন্ন জায়গায় বরাদ্দ ঘটে:

  1. আপনি যখন newআক্ষরিক বাক্য গঠন বা এর মাধ্যমে কোনও বস্তু তৈরি করেন [...]বা {}
  2. আপনি যখন স্ট্রিং কনটেনেট করেন।
  3. আপনি যখন এমন স্কোপ সন্নিবেশ করেন যাতে ফাংশন ঘোষণা থাকে।
  4. আপনি যখন কোনও ক্রিয়া সম্পাদন করেন যা ব্যতিক্রম ঘটায়।
  5. আপনি যদি একটি ফাংশন অভিব্যক্তি নির্ণয় কখন: (function (...) { ... })
  6. আপনি যখন এমন কোনও ক্রিয়াকলাপ সম্পাদন করেন যা পছন্দ করতে Object(myNumber)বা পছন্দ করতে পারেNumber.prototype.toString.call(42)
  7. আপনি যখন কোনও বিল্টিনকে কল করেন যা হুডের নীচে এর যে কোনও একটি করে, পছন্দ করে Array.prototype.slice
  8. আপনি যখন argumentsপ্যারামিটার তালিকার উপর প্রতিবিম্বিত করতে ব্যবহার করেন।
  9. যখন আপনি একটি স্ট্রিং বিভক্ত হন বা একটি নিয়মিত প্রকাশের সাথে মেলে।

এগুলি করা থেকে বিরত থাকুন এবং যেখানে সম্ভব সম্ভব জিনিসগুলি পুল এবং পুনরায় ব্যবহার করুন।

বিশেষত: এর জন্য সুযোগগুলি সন্ধান করুন:

  1. অভ্যন্তরীণ ফাংশনগুলিকে টানুন যা ক্লোজ-ওভারের স্টেটের উপর কোনও বা কয়েকটি নির্ভরতা নেই একটি উচ্চতর, দীর্ঘস্থায়ী স্কোপে। (কিছু কোড মিনিফায়ার যেমন ক্লোজার সংকলক অভ্যন্তরীণ ফাংশনগুলিকে ইনলাইন করতে পারে এবং আপনার জিসির কার্যকারিতা উন্নত করতে পারে))
  2. কাঠামোগত ডেটা উপস্থাপন করতে বা গতিশীল ঠিকানা দেওয়ার জন্য স্ট্রিংগুলি ব্যবহার করা এড়িয়ে চলুন। বিশেষ করে বার বার পার্সিং splitবা নিয়মিত এক্সপ্রেশন ম্যাচগুলি এড়িয়ে চলুন কারণ প্রত্যেকটির একাধিক অবজেক্ট বরাদ্দ প্রয়োজন। এটি প্রায়শই অনুসন্ধান সারণী এবং গতিশীল ডোম নোড আইডিগুলির কীগুলির সাথে ঘটে। উদাহরণস্বরূপ, lookupTable['foo-' + x]এবং document.getElementById('foo-' + x)উভয় একটি বরাদ্দ জড়িত যেহেতু একটি স্ট্রিং কনটেন্টেশন রয়েছে। প্রায়শই আপনি পুনর্বিবেচনার পরিবর্তে দীর্ঘস্থায়ী বস্তুগুলিতে কীগুলি সংযুক্ত করতে পারেন। আপনার সমর্থন করা ব্রাউজারগুলির উপর নির্ভর করে আপনি Mapসরাসরি কী হিসাবে অবজেক্টগুলি ব্যবহার করতে সক্ষম হতে পারেন ।
  3. সাধারণ কোড-পাথগুলিতে ব্যতিক্রম ধরা এড়ান। পরিবর্তে try { op(x) } catch (e) { ... }, না if (!opCouldFailOn(x)) { op(x); } else { ... }
  4. আপনি যখন স্ট্রিং তৈরি করা এড়াতে পারবেন না, যেমন কোনও সার্ভারে কোনও বার্তা প্রেরণ করতে, এমন একটি বিল্টিন ব্যবহার করুন JSON.stringifyযা একাধিক অবজেক্ট বরাদ্দ করার পরিবর্তে সামগ্রী সংগ্রহ করতে অভ্যন্তরীণ নেটিভ বাফার ব্যবহার করে।
  5. উচ্চ-ফ্রিকোয়েন্সি ইভেন্টগুলির জন্য কলব্যাকগুলি ব্যবহার করা এড়িয়ে চলুন এবং আপনি যেখানে পারেন সেখানে কলব্যাক হিসাবে একটি দীর্ঘকালীন ফাংশনটি পাস করুন (দেখুন 1) যা বার্তার সামগ্রী থেকে রাষ্ট্রটিকে পুনরায় তৈরি করে।
  6. argumentsযখন ডাকা হয় তখন অ্যারে-এর মতো অবজেক্ট তৈরি করতে হয় এমন ফাংশনগুলি ব্যবহার করা থেকে বিরত থাকুন।

আমি JSON.stringifyবহির্গামী নেটওয়ার্ক বার্তা তৈরি করতে ব্যবহার করার পরামর্শ দিয়েছি । JSON.parseস্পষ্টতই ব্যবহার করে ইনপুট বার্তাগুলি পার্স করা অবশ্যই বরাদ্দকে জড়িত করে এবং এর মধ্যে অনেকগুলি বড় বার্তার জন্য। আপনি যদি আগত বার্তাগুলিকে আদিমাগুলির অ্যারে হিসাবে উপস্থাপন করতে পারেন তবে আপনি প্রচুর বরাদ্দ সংরক্ষণ করতে পারেন। কেবলমাত্র অন্যান্য বিল্টিন যার আশেপাশে আপনি কোনও পার্সার তৈরি করতে পারেন যা বরাদ্দ দেয় না String.prototype.charCodeAt। জটিল ফর্ম্যাটটির একটি পার্সার যা কেবলমাত্র পড়ার জন্য নরক হতে চলেছে তা ব্যবহার করে।


আপনি কি মনে করেন না যে JSON.parsed বস্তুগুলি বার্তার স্ট্রিংয়ের চেয়ে কম (বা সমান) স্থান বরাদ্দ করে?
বার্গি

@ বেরগি, এটি সম্পত্তির নামগুলির পৃথক বরাদ্দ প্রয়োজন কিনা তার উপর নির্ভর করে, তবে পার্স গাছের পরিবর্তে ইভেন্ট তৈরি করে এমন পার্সার কোনও বহিরাগত বরাদ্দ রাখে না।
মাইক স্যামুয়েল

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

অনুগ্রহের সাথে আমার খারাপ সময় নির্ধারণের জন্য আমি এটির শীর্ষে একটি অতিরিক্ত যুক্ত করেছি (200 ন্যূনতম আমি দিতে পারছিলাম;) - কোনও কারণে যদিও এটি প্রদানের আগে আমাকে 24 ঘন্টা অপেক্ষা করতে হবে (যদিও আমি 'বিদ্যমান উত্তর পুরষ্কার' নির্বাচন করেছি)। আগামীকাল আপনার হবে ...
আপড্রিপ

@ ইউপিকেক্রিক, কোনও উদ্বেগ নেই। আপনি এটি দরকারী বলে খুশি।
মাইক স্যামুয়েল

12

ক্রোম ডেভেলপার টুলস মেমরি অ্যালোকেশন ট্রেসিং জন্য একটি খুব সুন্দর বৈশিষ্ট্য আছে। একে মেমরি টাইমলাইন বলে called এই নিবন্ধটি কিছু বিশদ বর্ণনা করে। আমি মনে করি আপনি এই "সটি টুথ" এর কথা বলছেন? এটি বেশিরভাগ GC'ed রানটাইমগুলির জন্য স্বাভাবিক আচরণ। ব্যবহারের প্রান্তিক সংগ্রহটি ট্রিগার করতে না আসা পর্যন্ত বরাদ্দ এগিয়ে চলে। সাধারণত বিভিন্ন থ্রেশহোল্ডে বিভিন্ন ধরণের সংগ্রহ রয়েছে।

ক্রোমে মেমরির টাইমলাইন

আবর্জনা সংগ্রহগুলি তাদের সময়কালের সাথে ট্রেসের সাথে যুক্ত ইভেন্ট তালিকার অন্তর্ভুক্ত। আমার বরং পুরানো নোটবুকটিতে, সাময়িক কালেকশনগুলি প্রায় 4 এমবিতে হয় এবং 30 মিমি নিয়ে থাকে। এটি আপনার 60Hz লুপের পুনরাবৃত্তির 2 2 যদি এটি অ্যানিমেশন হয় তবে 30 মিমি সংগ্রহগুলি সম্ভবত বিশৃঙ্খলা সৃষ্টি করে। আপনার পরিবেশে কী চলছে তা দেখার জন্য আপনার এখানে শুরু করা উচিত: সংগ্রহের চৌম্বকটি কোথায় এবং আপনার সংগ্রহগুলি কতক্ষণ নিচ্ছে। এটি আপনাকে অনুকূলকরণগুলি মূল্যায়নের জন্য একটি রেফারেন্স পয়েন্ট দেয় point তবে আপনি সম্ভবত বরাদ্দের হারকে কমিয়ে, সংগ্রহের মধ্যবর্তী ব্যবধানটি দীর্ঘায়িত করে তোলা স্টাটারের ফ্রিকোয়েন্সি হ্রাস করার চেয়ে ভাল কিছু করতে পারবেন না।

পরবর্তী পদক্ষেপটি প্রোফাইলগুলি ব্যবহার করা রেকর্ড টাইপ অনুসারে বরাদ্দের একটি ক্যাটালগ তৈরি করতে রেকর্ড হিপ বরাদ্দ বৈশিষ্ট্য। এটি খুব শীঘ্রই চিহ্নিত করবে যে কোন অবজেক্টের ধরণগুলি ট্রেস পিরিয়ডের সময় সর্বাধিক স্মৃতি গ্রহণ করছে, যা বরাদ্দ হারের সমতুল্য। হারের ক্রম বর্ধমান ক্রমে এইগুলিতে ফোকাস করুন।

কৌশলগুলি রকেট বিজ্ঞান নয়। বাক্সযুক্ত বস্তুগুলি এড়িয়ে চলুন যখন আপনি একটি আনবক্স করা না করতে পারেন। প্রতিটি পুনরাবৃত্তিতে নতুন করে বরাদ্দ দেওয়ার পরিবর্তে একক বাক্সযুক্ত বস্তু ধরে রাখতে এবং পুনরায় ব্যবহার করতে গ্লোবাল ভেরিয়েবলগুলি ব্যবহার করুন। সাধারণ কমন অবজেক্টের ধরণগুলি ফ্রি তালিকায় ছেড়ে দেওয়ার পরিবর্তে ফ্রি তালিকায় রাখুন। ক্যাশে স্ট্রিং কনটেনটেশন ফলাফল যা ভবিষ্যতের পুনরাবৃত্তিতে সম্ভবত পুনরায় ব্যবহারযোগ্য। পরিবর্তে কোনও বন্ধের সুযোগে ভেরিয়েবলগুলি সেট করে ফাংশন ফলাফলগুলি ফেরত দিতে বরাদ্দ এড়াবেন। সেরা কৌশলটি খুঁজতে আপনাকে প্রতিটি বস্তুর প্রকারের নিজস্ব প্রসঙ্গে বিবেচনা করতে হবে। আপনার যদি সুনির্দিষ্ট সাহায্যের প্রয়োজন হয় তবে আপনি যে চ্যালেঞ্জটি দেখছেন তার বিশদ বর্ণনা করে একটি সম্পাদনা পোস্ট করুন।

আমি কোনও শটগান কম জঞ্জাল তৈরির প্রয়াসে একটি অ্যাপ্লিকেশন জুড়ে আপনার সাধারণ কোডিং শৈলীটি বিকৃত করার বিরুদ্ধে পরামর্শ দিচ্ছি। এটি একই কারণে আপনার অকাল গতির জন্য অপ্টিমাইজ করা উচিত নয়। আপনার বেশিরভাগ প্রচেষ্টার সাথে যুক্ত হওয়া জটিলতা এবং কোডের অস্পষ্টতা অনেকটাই অর্থহীন হবে।


ঠিক আছে, আমি বোঝাতে চাই আমি জানি যে সবসময় কোনও ধরণের একটি কাঠের ধরণের প্যাটার্ন থাকবে তবে আমার উদ্বেগটি হ'ল আমার অ্যাপ্লিকেশনটির সাথে সাটোথ ফ্রিকোয়েন্সি এবং 'ক্লিফস' বেশ উচ্চ। মজার ব্যাপার হচ্ছে, জিসি ঘটনা আমার টাইমলাইনে এ প্রদর্শিত হবে না - সেই ইভেন্টের 'রেকর্ড' পেন (মধ্যম একটি) প্রদর্শিত হয়: request animation frame, animation frame fired, এবং composite layers। আমি জানি না কেন আমি GC Eventআপনার মতো দেখতে পাচ্ছি না (এটি ক্রোমের সর্বশেষ সংস্করণে এবং ক্যানারিও রয়েছে)।
আপক্রিক

4
আমি 'রেকর্ড হিপ বরাদ্দ' দিয়ে প্রোফাইলারটি ব্যবহার করার চেষ্টা করেছি কিন্তু এখনও পর্যন্ত এটি খুব কার্যকর হয়নি। সম্ভবত এটি কারণ আমি এটি সঠিকভাবে ব্যবহার করতে জানি না। এটি উল্লেখগুলি পূর্ণ বলে মনে হচ্ছে যা আমার কাছে কিছুই বোঝায় না, যেমন @342342এবং code relocation info
আপক্রিক

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

9

একটি সাধারণ নীতি হিসাবে আপনি যতটা সম্ভব ক্যাশে করতে চান এবং আপনার লুপের প্রতিটি রানের জন্য তৈরি এবং ধ্বংস করতে যতটা করতে চান।

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

var options = {var1: value1, var2: value2, ChangingVariable: value3};
function loopfunc()
{
    //do something
}

while(true)
{
    $.each(listofthings, loopfunc);

    options.ChangingVariable = newvalue;
    someOtherFunction(options);
}

এর চেয়ে অনেক বেশি দ্রুত দৌড়াতে হবে:

while(true)
{
    $.each(listofthings, function(){
        //do something on the list
    });

    someOtherFunction({
        var1: value1,
        var2: value2,
        ChangingVariable: newvalue
    });
}

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

আপনি ইতিমধ্যে যা চেষ্টা করেছেন এবং যা ভেবে দেখেছেন তার তুলনায় এটি যদি কিছুটা তুচ্ছ হয় Sorry


এই. এছাড়াও অন্যান্য ফাংশনগুলির মধ্যে উল্লিখিত ফাংশনগুলি (এটি আইআইএফই নয়) এটি সাধারণ অপব্যবহার যা প্রচুর স্মৃতি পোড়ায় এবং সহজেই মিস করা যায়।
ইসাইলিজা

ধন্যবাদ ক্রিস! দুর্ভাগ্যক্রমে আমার কোনও ডাউনটাইম নেই: /
আপসক্রিক

4

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

অবশ্যই কোডের সর্বত্র এটি করা যায়নি, তবে সাধারণত আবর্জনা সংগ্রহকারী এড়ানোর আমার উপায়।

পিএস এটি কোডের নির্দিষ্ট অংশটিকে সামান্য কম রক্ষণাবেক্ষণ করতে পারে।


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