জাভাতে মেমরি ফাঁস কীভাবে তৈরি করবেন?


3221

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

একটি উদাহরণ কি হবে?


275
আমি তাদের বলব যে জাভা কোনও আবর্জনা সংগ্রহকারী ব্যবহার করে এবং তাদের "মেমরি ফাঁস" এর সংজ্ঞা সম্পর্কে কিছুটা সুনির্দিষ্ট হওয়ার জন্য বলে, এটি ব্যাখ্যা করে যে - জেভিএম বাগগুলি বাদ দেওয়া - জাভা একেবারে একই পদ্ধতিতে মেমরি ফাঁস করতে পারে না / সি ++ পারেন। আপনার কোথাও অবজেক্টের রেফারেন্স থাকতে হবে ।
দারিয়ান

371
আমি মজার বিষয়বোধ করি যে সর্বাধিক উত্তরে লোকেরা সেই প্রান্তের মামলা এবং কৌশলগুলি সন্ধান করে এবং মনে হয় যে বিন্দুটি সম্পূর্ণরূপে অনুপস্থিত (আইএমও)। তারা কেবল এমন কোডটি প্রদর্শন করতে পারে যা অবজেক্টের কাছে অকেজো রেফারেন্স রাখে যা আর কখনও ব্যবহার করবে না এবং একই সাথে এই রেফারেন্সগুলি কখনই ছাড়বে না; কেউ বলতে পারে যে এই ঘটনাগুলি "সত্য" মেমরি ফাঁস নয় কারণ আশেপাশে সেই সমস্ত অবজেক্টের রেফারেন্স রয়েছে তবে প্রোগ্রামটি যদি আবার সেই উল্লেখগুলি আবার ব্যবহার না করে এবং এগুলি কখনও না ফেলে তবে এটি সম্পূর্ণরূপে (এবং হিসাবে খারাপ) সত্য স্মৃতি ফাঁস "।
এহবকোস্ট

62
সত্যই আমি "গো" সম্পর্কে জিজ্ঞাসা করা অনুরূপ প্রশ্নটি -১ এ নেমে গেছে বলে বিশ্বাস করতে পারি না। এখানে: stackoverflow.com/questions/4400311/... মূলত মেমরি তথ্য ফাঁসের আমি সম্পর্কে কথা ছিল বেশী ওপি করার +200 upvotes পেয়েছিলাম এবং এখনো আমি আক্রমণ করে এবং যদি "যান" একই সমস্যা ছিল জিজ্ঞাসা করার জন্য অপমানিত করেন। কোনওভাবেই আমি নিশ্চিত নই যে সমস্ত উইকি জিনিসটি দুর্দান্তভাবে কাজ করছে।
SyntaxT3rr0r

74
@ সিনট্যাক্সটি 3rr0r - ডারিয়েনের উত্তর ফ্যানবায়াইজম নয়। তিনি স্পষ্টভাবে স্বীকার করেছেন যে নির্দিষ্ট কিছু জেভিএমের বাগ থাকতে পারে যার অর্থ স্মৃতি ফাঁস হয়ে যায়। এটি মেমরি ফুটোয়ের জন্য ভাষা অনুমানের থেকে আলাদা।
পিটার পুনর্বার

31
@ এহাবকোস্ট: না, তারা সমতুল্য নয়। (1) আপনি মেমোরিটিকে পুনরায় দাবি করার ক্ষমতা রাখেন, তবে "সত্যিকারের ফাঁস" এর মধ্যে আপনার সি / সি ++ প্রোগ্রাম বরাদ্দকৃত সীমাটি ভুলে যায়, পুনরুদ্ধারের কোনও নিরাপদ উপায় নেই। (২) আপনি প্রোফাইলিংয়ের মাধ্যমে সমস্যাটি খুব সহজেই সনাক্ত করতে পারেন, কারণ "ফোটা" কী কী জিনিসকে জড়িত তা আপনি দেখতে পারেন। (৩) একটি "সত্যিকারের ফাঁস" একটি দ্ব্যর্থহীন ত্রুটি, যদিও এমন একটি প্রোগ্রাম যা সমাপ্ত হওয়া অবধি প্রচুর পরিমাণে অবজেক্ট রাখে এটি কীভাবে কাজ করার উদ্দেশ্যে বোঝানো হচ্ছে তার একটি ইচ্ছাকৃত অংশ হতে পারে।
দারিয়েন

উত্তর:


2309

খাঁটি জাভাতে সত্যিকারের মেমরি ফুটো (কোডগুলি চালিয়ে যাওয়া অ্যাক্সেসযোগ্য তবে এখনও মেমরিতে সংরক্ষণ করা আছে) তৈরি করার জন্য এখানে একটি ভাল উপায়:

  1. অ্যাপ্লিকেশনটি দীর্ঘ-চলমান থ্রেড তৈরি করে (বা আরও দ্রুত ফুটো করার জন্য একটি থ্রেড পুল ব্যবহার করুন)।
  2. থ্রেড একটি (allyচ্ছিকভাবে কাস্টম) এর মাধ্যমে শ্রেণি লোড করে ClassLoader
  3. শ্রেণিটি মেমরির একটি বৃহত অংশ বরাদ্দ করে (উদাঃ new byte[1000000]), এটির একটি দৃ reference় রেফারেন্স একটি স্ট্যাটিক ক্ষেত্রে সংরক্ষণ করে এবং তারপরে একটিতে নিজের একটি রেফারেন্স সঞ্চয় করে ThreadLocal। অতিরিক্ত মেমরি বরাদ্দ করা alচ্ছিক (শ্রেণীর উদাহরণ ফাঁস যথেষ্ট) তবে এটি ফাঁসের কাজটি আরও দ্রুত করে তুলবে।
  4. অ্যাপ্লিকেশনটি কাস্টম ক্লাসের সমস্ত উল্লেখ বা ClassLoaderএটি লোড করা হয়েছিল।
  5. পদ্ধতি পুনরাবৃত্তি করুন।

উপায়টি ThreadLocalওরাকলের জেডিকে বাস্তবায়নের কারণে, এটি একটি মেমরি ফাঁস তৈরি করে:

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

এই উদাহরণে, শক্তিশালী রেফারেন্সগুলির শৃঙ্খলাটি এরকম দেখাচ্ছে:

Threadঅবজেক্ট → threadLocalsমানচিত্র example উদাহরণ শ্রেণীর উদাহরণ class উদাহরণ শ্রেণি → স্থির ThreadLocalক্ষেত্র → ThreadLocalঅবজেক্ট।

(এই ClassLoaderফাঁস তৈরিতে সত্যই ভূমিকা রাখে না, এই অতিরিক্ত রেফারেন্স চেইনের কারণে এটি ফাঁসকে আরও খারাপ করে তোলে: উদাহরণস্বরূপ শ্রেণি → ClassLoader→ এটি যে সমস্ত ক্লাসে লোড হয়েছে। অনেক জেভিএম বাস্তবায়নে এটি আরও খারাপ ছিল, বিশেষত পূর্বে জাভা,, কারণ ক্লাস এবং ClassLoaderএসগুলি সরাসরি পার্জেজে বরাদ্দ করা হয়েছিল এবং কখনই আবর্জনা সংগ্রহ করা হয়নি were)

এই প্যাটার্নটির একটি ভিন্নতা হ'ল অ্যাপ্লিকেশন পাত্রে (টমক্যাটের মতো) যদি আপনি ঘন ঘন অ্যাপ্লিকেশনগুলি পুনরায় বিতরণ করেন যা কোনওভাবে ThreadLocalনিজের কাছে ফিরে আসে তবে অ্যাপ্লিকেশন পাত্রে একটি চালনীয়ের মতো মেমরি ফাঁস হয়। এটি বেশ কয়েকটি সূক্ষ্ম কারণে ঘটতে পারে এবং প্রায়শই ডিবাগ করা এবং / অথবা ঠিক করা কঠিন।

আপডেট : যেহেতু প্রচুর লোকেরা এটির জন্য জিজ্ঞাসা করে, তাই এখানে কয়েকটি উদাহরণ কোড রয়েছে যা এই আচরণটিকে কার্যত দেখায়


186
+1 ClassLoader লিকগুলি JEE বিশ্বে সবচেয়ে সাধারণভাবে বেদনাদায়ক মেমরি ফাঁস হয় যা প্রায়শই তৃতীয় পক্ষের লিবসের ফলে ঘটে যা তথ্যকে রূপান্তর করে (বিয়ানইটিসস, এক্সএমএল / জেএসএন কোডেক)। আপনার অ্যাপ্লিকেশনটির রুট ক্লাসলোডারের বাইরে লিবটি লোড হয়ে গেলে তবে এটি আপনার ক্লাসের রেফারেন্স রাখে (উদাহরণস্বরূপ ক্যাশে করে) এমনটি ঘটতে পারে। আপনি যখন নিজের অ্যাপ্লিকেশনটিকে অপ্রকাশিত / পুনরায় প্রচার করবেন তখন জেভিএম অ্যাপ্লিকেশনটির ক্লাসলোডারকে আবর্জনা সংগ্রহ করতে অক্ষম (এবং তাই এটি দ্বারা লোড করা সমস্ত শ্রেণি), সুতরাং পুনরাবৃত্তি সহ অ্যাপ্লিকেশন সার্ভারটি শেষ পর্যন্ত বার্কগুলিকে মোতায়েন করে। ভাগ্যবান যদি আপনি ক্লাসকাস্টএক্সপশন zxyAbc এর সাথে একটি সূত্র পান তবে zxyAbc এ কাস্ট করা যাবে না
earcam

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

57
+1: ক্লাসলোডার ফাঁস একটি দুঃস্বপ্ন। আমি তাদের বের করার চেষ্টা করে সপ্তাহ কাটিয়েছি। দুঃখজনক বিষয় হ'ল, @ ক্যামকাম যা বলেছেন, সেগুলি বেশিরভাগ তৃতীয় পক্ষের লিবার কারণে হয় এবং বেশিরভাগ প্রোফাইলাররা এই ফাঁসগুলি সনাক্ত করতে পারেন না। ক্লাসলোডার ফাঁস সম্পর্কে এই ব্লগে একটি ভাল এবং স্পষ্ট ব্যাখ্যা রয়েছে। ব্লগস.অরাকল.com
অ্যাড্রিয়ান এম

4
@ নিকোলাস: আপনি কি নিশ্চিত? জ্রোকিত জিসি ক্লাস অবজেক্টগুলি ডিফল্টরূপে করেন এবং হটস্পট তা করেন না, তবে এএফআইকে জেআরোকিত এখনও থ্রেডলোকাল দ্বারা রেফারেন্সযুক্ত কোনও ক্লাস বা ক্লাসলোডার জিসি করতে পারেন না।
ড্যানিয়েল প্রাইডেন

6
টমক্যাট আপনার জন্য এই ফাঁসগুলি সনাক্ত করার চেষ্টা করবে এবং তাদের সম্পর্কে সতর্ক করবে: wiki.apache.org/tomcat/ মেমরিলিকপ্রোটেকশন । অতি সাম্প্রতিক সংস্করণটি আপনার জন্য মাঝে মাঝে লিকটি ঠিক করে দেবে।
ম্যাথিজস বীরম্যান

1212

স্ট্যাটিক ফিল্ড হোল্ডিং অবজেক্ট রেফারেন্স [esp ফাইনাল ফিল্ড]

class MemorableClass {
    static final ArrayList list = new ArrayList(100);
}

String.intern()লম্বা স্ট্রিংয়ে ফোন করা

String str=readString(); // read lengthy string any source db,textbox/jsp etc..
// This will place the string in memory pool from which you can't remove
str.intern();

(অনাবদ্ধ) মুক্ত স্ট্রিম (ফাইল, নেটওয়ার্ক ইত্যাদি ...)

try {
    BufferedReader br = new BufferedReader(new FileReader(inputFile));
    ...
    ...
} catch (Exception e) {
    e.printStacktrace();
}

অনাবৃত সংযোগগুলি

try {
    Connection conn = ConnectionFactory.getConnection();
    ...
    ...
} catch (Exception e) {
    e.printStacktrace();
}

অঞ্চলগুলি যা জেভিএমের আবর্জনা সংগ্রাহকের কাছ থেকে অ্যাক্সেসযোগ্য নয় , যেমন দেশীয় পদ্ধতির মাধ্যমে বরাদ্দ করা মেমরি

ওয়েব অ্যাপ্লিকেশনগুলিতে, অ্যাপ্লিকেশন স্পষ্টভাবে বন্ধ বা অপসারণ না করা অবধি কিছু বস্তু অ্যাপ্লিকেশন স্কোপে সংরক্ষণ করা হয়।

getServletContext().setAttribute("SOME_MAP", map);

ভুল বা অনুপযুক্ত জেভিএম বিকল্পগুলি , যেমন noclassgcআইবিএম জেডিকে বিকল্প যা অব্যবহৃত শ্রেণির আবর্জনা সংগ্রহকে বাধা দেয়

দেখুন আইবিএম JDK সেটিংস


178
আমি প্রসঙ্গে ও সেশনের বৈশিষ্ট্যগুলি "ফুটো" হওয়াতে দ্বিমত পোষণ করব। তারা কেবল দীর্ঘকালীন ভেরিয়েবল। এবং স্থির চূড়ান্ত ক্ষেত্র কমবেশি কেবল একটি ধ্রুবক। সম্ভবত বড় ধ্রুবকগুলি এড়ানো উচিত, তবে আমি এটিকে মেমরি ফুটো বলা ঠিক মনে করি না।
ইয়ান ম্যাকলেয়ার্ড

80
(অনাবৃত) উন্মুক্ত স্ট্রিম (ফাইল, নেটওয়ার্ক ইত্যাদি ...) চূড়ান্তকরণের সময়, বাস্তবের জন্য ফুটো হয় না (যা পরবর্তী জিসি চক্রের পরে হবে) বন্ধ () নির্ধারিত হতে চলেছে ( close()সাধারণত চূড়ান্তকরণে অন্তর্ভুক্ত থাকে না) থ্রেড যেহেতু একটি ব্লকিং অপারেশন হতে পারে)। এটি বন্ধ না করা একটি খারাপ অভ্যাস, তবে এটি ফুটো হওয়ার কারণ নয়। অনাবদ্ধ java.sql. সংযোগ একই।
16:38

33
বেশিরভাগ বুদ্ধিমান জেভিএমগুলিতে, এটি প্রদর্শিত হয় যদিও স্ট্রিং ক্লাসটির হ্যাশটেবল সামগ্রীতে কেবলমাত্র একটি দুর্বল রেফারেন্স রয়েছে intern। যেমন, এটি সঠিকভাবে সংগ্রহ করা আবর্জনা নয় কোনও ফুটো। (তবে আইএএনএজেপি) মাইন্ডপ্রড.com
ম্যাট বি

42
স্ট্যাটিক ফিল্ড হোল্ডিং অবজেক্ট রেফারেন্স [esp ফাইনাল ফিল্ড] মেমরি লিক কীভাবে ??
কানাগাভেলু সুগুমার

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

460

একটি সহজ কাজ হ'ল একটি ভুল (বা অস্তিত্বহীন) hashCode()বা একটি হ্যাশসেট ব্যবহার করা equals()এবং তারপরে "নকল" যোগ করা চালিয়ে যাওয়া। সদৃশগুলি যেমনটি হওয়া উচিত তা উপেক্ষা করার পরিবর্তে সেটটি কেবল কখনও বাড়বে এবং আপনি সেগুলি সরাতে পারবেন না।

আপনি যদি এই খারাপ কীগুলি / উপাদানগুলির চারদিকে ঝুলতে চান তবে আপনি একটি স্ট্যাটিক ফিল্ড ব্যবহার করতে পারেন

class BadKey {
   // no hashCode or equals();
   public final String key;
   public BadKey(String key) { this.key = key; }
}

Map map = System.getProperties();
map.put(new BadKey("key"), "value"); // Memory leak even if your threads die.

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

12
@ ডোনাল আমি যা বলতে চাইছি, আমি অনুমান করি, আমি কি কোনও স্মৃতি ফাঁসের আপনার সংজ্ঞার সাথে একমত নই? আমি আপনার পুনরুক্তি-অপসারণ কৌশলটি ফুটোয়ের নীচে ড্রিপ-প্যান হিসাবে বিবেচনা করব (উপমা চালিয়ে যেতে); ড্রিপ প্যান নির্বিশেষে লিকটি এখনও বিদ্যমান।
কর্সিকা

94
আমি একমত, এই হল না , একটি মেমরি "লিক" কারণ আপনি শুধু hashset উল্লেখ মুছে ফেলুন এবং, এবং প্রবঁচনাময় পদাঘাত করতে জিসি জন্য অপেক্ষা করতে পারেন! স্মৃতি ফিরে যায়।
user541686

12
@ সিনট্যাক্সটি 3 আরআর0r, আমি আপনার প্রশ্নটিকে এমন জিজ্ঞাসা করে ব্যাখ্যা করেছি যে ভাষায় এমন কিছু আছে যা স্বাভাবিকভাবেই স্মৃতি ফাঁস করে দেয়? উত্তর না হয়। এই প্রশ্নগুলি জিজ্ঞাসা করে যে কোনও মেমরি ফুটোয়ের মতো কিছু তৈরি করার জন্য কোনও পরিস্থিতি তৈরি করা সম্ভব কিনা। সি / সি ++ প্রোগ্রামার যেভাবে বুঝতে পারে সেগুলির মধ্যে মেমরি ফুটো এই উদাহরণগুলির মধ্যে কোনওটিই নয়।
পিটার লরি

11
@ পিটার ল্যারি: এছাড়াও, আপনি এ সম্পর্কে কী ভাবেন: "সি ভাষায় এমন কিছু নেই যা স্বাভাবিকভাবেই মেমরি ফাঁস হয়ে যায় যদি আপনি বরাদ্দকৃত স্মৃতি ম্যানুয়ালি মুক্ত করতে ভুলবেন না" । বৌদ্ধিক অসততার জন্য তা কীভাবে হবে? যাইহোক, আমি ক্লান্ত: আপনার শেষ কথাটি থাকতে পারে।
SyntaxT3rr0r

271

নীচে একটি অ-স্পষ্ট কেস থাকবে যেখানে ভুলে যাওয়া শ্রোতার স্ট্যান্ডার্ড কেস, স্থিতিক রেফারেন্স, হ্যাশম্যাপে বোগাস / পরিবর্তনযোগ্য কীগুলি বা তাদের জীবনচক্রটি শেষ করার কোনও সুযোগ ছাড়াই কেবল থ্রেড আটকে রয়েছে Java

  • File.deleteOnExit() - সর্বদা স্ট্রিং ফাঁস, যদি স্ট্রিংটি সাবস্ট্রিং হয় তবে লিকটি আরও খারাপ হয় (অন্তর্নিহিত চরটি [] এছাড়াও ফাঁস হয়)- জাভাতে 7 টি স্ট্রিংগুলিও অনুলিপি করে char[], সুতরাং পরে প্রয়োগ হয় না ; @ ড্যানিয়েল, যদিও ভোটের দরকার নেই।

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

  • Runtime.addShutdownHookএবং অপসারণ না ... এবং তারপরে এমনকি স্ট্রেডগ্রুপ শ্রেণিতে একটি ত্রুটিযুক্ত স্ট্র্যাডগ্রুপের কারণে স্ট্রেটগ্রুপটি সংগ্রহ না করা হতে পারে, থ্রেডগ্রুপটি কার্যকরভাবে ফাঁস হতে পারে। গসিপরোউটারে জেগ্রুপের ফুটো আছে।

  • তৈরি করা হচ্ছে, তবে শুরু হচ্ছে না, Threadউপরের মত একই বিভাগে চলেছে।

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

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

  • ThreadGroup.destroy()থ্রেডগ্রুপের কোনও থ্রেড না থাকলে কল করা , তবে এটি চাইল্ড থ্রেডগ্রুপ রাখে। একটি খারাপ ফুটো যা থ্রেডগ্রুপকে তার পিতামাতার কাছ থেকে অপসারণ করতে বাধা দেবে, তবে সমস্ত বাচ্চা অগণিত হবে।

  • WeakHashMap এবং মানটি (ইন) সরাসরি কীটি উল্লেখ করে। হিপ ডাম্প ছাড়া এটি খুঁজে পাওয়া শক্ত। এটি সমস্ত বর্ধিত ক্ষেত্রে প্রযোজ্য Weak/SoftReferenceযা রক্ষিত অবজেক্টটিতে কোনও শক্ত রেফারেন্স রাখতে পারে।

  • ব্যবহার java.net.URLhttp (s) প্রোটোকল সঙ্গে থেকে সংস্থান লোড (!)। এটি একটি বিশেষ, এটি KeepAliveCacheথ্রেডগ্রুপ সিস্টেমে একটি নতুন থ্রেড তৈরি করে যা বর্তমান থ্রেডের প্রসঙ্গে ক্লাসলোডার ফাঁস করে। থ্রেডটি প্রথম অনুরোধের ভিত্তিতে তৈরি করা হয় যখন কোনও জীবন্ত থ্রেড উপস্থিত না থাকে, সুতরাং আপনি ভাগ্যবান হতে পারেন বা কেবল ফাঁস হন। ফাঁস ইতিমধ্যে জাভা 7 এ স্থির হয়েছে এবং থ্রেড সঠিকভাবে তৈরি করা কোডটি প্রসঙ্গ শ্রেণিবদ্ধকে সরিয়ে দেয়।আরও কয়েকটি মামলা রয়েছে (ইমেজফ্যাচারের মতো, এছাড়াও নির্দিষ্ট অনুরূপ থ্রেড তৈরি করার)।

  • ব্যবহার InflaterInputStreamক্ষণস্থায়ী new java.util.zip.Inflater()কন্সট্রাকটর মধ্যে ( PNGImageDecoderউদাহরণস্বরূপ) এবং কলিং না end()inflater করুন। ঠিক আছে, আপনি যদি কন্সট্রাক্টরে ন্যায্য new, কোনও সুযোগ না দিয়ে পাস করেন ... এবং হ্যাঁ, close()স্ট্রিমটিতে কল করা যদি ম্যানুয়ালি কন্সট্রাক্টর প্যারামিটার হিসাবে পাস হয় তবে এটি স্ফীতকটি বন্ধ করে না। এটি সত্যিকারের ফাঁস নয় কারণ এটি চূড়ান্তকরণকারী দ্বারা প্রকাশ করা হবে ... যখন এটি প্রয়োজনীয় মনে করবে ems এই মুহুর্ত পর্যন্ত এটি নেটিভ স্মৃতি এত খারাপভাবে খায় এটি লিনাক্স oom_killer কে দায়মুক্তি দিয়ে প্রক্রিয়াটি মেরে ফেলতে পারে। মূল সমস্যাটি হ'ল জাভাতে চূড়ান্তকরণ খুব বিশ্বাসযোগ্য নয় এবং জি 1 এটি 7.0.2 অবধি খারাপ করেছে। গল্পটির নৈতিকতা: যত তাড়াতাড়ি সম্ভব স্থানীয় উত্সগুলি ছেড়ে দিন; ফাইনালাইজারটি খুব গরিব।

  • একই ক্ষেত্রে java.util.zip.Deflater। এটি ডিফ্লেটার জাভাতে ক্ষুধার্ত স্মৃতিশক্তি হওয়ায় এটি আরও খারাপ, অর্থাত্ সর্বদা 15 বিট (সর্বোচ্চ) এবং 8 মেমরি স্তর (9 ম্যাক্সিমাম) ব্যবহার করে কয়েকশ কেবি কে দেশীয় মেমরি বরাদ্দ করে। ভাগ্যক্রমে, Deflaterব্যাপকভাবে ব্যবহৃত হয় না এবং আমার জ্ঞানের জেডিকে কোনও অপব্যবহার নেই। end()আপনি নিজে নিজে একটি Deflaterবা তৈরি করলে সর্বদা কল করুন Inflater। শেষ দুটির সেরা অংশ: আপনি উপলব্ধ সাধারণ প্রোফাইলিং সরঞ্জামগুলির মাধ্যমে সেগুলি খুঁজে পাবেন না।

(অনুরোধের পরে আমি যে আরও কিছু সময় নষ্ট করেছিলাম তা যুক্ত করতে পারি))

নিরাপদে থাকো এবং রইল শুভ কামনা; ফাঁস খারাপ!


23
Creating but not starting a Thread...হ্যাঁ, কয়েক শতাব্দী আগে আমি এটিকে খারাপভাবে কামড়েছিলাম! (জাভা 1.3)
লিওনব্লাই

@ লেওনব্লয়, থ্রেড গ্রুপটিতে সরাসরি থ্রেড যুক্ত হওয়ার আগে এটি আরও খারাপ হওয়ার আগে, শুরু না করা মানে খুব শক্ত ফুটো ছিল। না এটা ঠিক বৃদ্ধি unstartedগণনা কিন্তু যে প্রতিরোধ (ক্ষুদ্রতর মন্দ কিন্তু এখনও একটি লিক) অন্তক থেকে থ্রেড গ্রুপ
bestsss

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

1
@ বেস্টেস: আমি কৌতূহলী, জেভিএম শাটডাউনটি ভালভাবে চলার কারণে আপনি কেন একটি শাটডাউন হুক মুছে ফেলতে চান?
লরেন্স ডল

203

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

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

তবে যে কোনও দীর্ঘস্থায়ী অ্যাপ্লিকেশন ভাগ করে নেওয়ার ঝোঁক রয়েছে। এটি কিছু হতে পারে, স্ট্যাটিকস, সিঙ্গলেটন ... প্রায়শই অ-তুচ্ছ অ্যাপ্লিকেশনগুলি জটিল বিষয়গুলির গ্রাফ তৈরি করে to কেবল নুলের জন্য একটি রেফারেন্স সেট করতে ভুলে যাওয়া বা প্রায়শই একটি সংগ্রহ থেকে একটি অবজেক্ট সরানো ভুলে যাওয়া মেমরি ফাঁস করার জন্য যথেষ্ট।

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

আমাদের কাছে একটি জটিল গ্রাফ থাকতে পারে যা পূর্ববর্তী অবস্থা সংরক্ষণ করে যা একটি গণনার দ্বারা প্রয়োজনীয়। তবে পূর্ববর্তী রাজ্য নিজেই এর আগে রাজ্যের সাথে যুক্ত ছিল এবং আরও অনেক কিছু।

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

একটি মেমরি ফাঁস সত্যই সম্ভব এবং পুরোপুরি অনুমানযোগ্য। বিশেষ ভাষার বৈশিষ্ট্য বা কোণার কেসের প্রয়োজন নেই। মেমরি ফাঁস হয় এমন একটি সূচক যে কোনও কিছু অনুপস্থিত বা এমনকি ডিজাইনের সমস্যা রয়েছে।


24
আমি মজার বিষয়বোধ করি যে অন্য উত্তরে লোকেরা সেই প্রান্তের মামলাগুলি এবং কৌশলগুলি সন্ধান করে এবং মনে হয় এটি বিন্দুটি পুরোপুরি অনুপস্থিত। তারা কেবল এমন কোড প্রদর্শন করতে পারে যা অবজেক্টের কাছে অকেজো রেফারেন্স রাখে যা আর কখনও ব্যবহার করবে না এবং সেই উল্লেখগুলি কখনই মুছে ফেলবে না; কেউ বলতে পারেন যে এই ঘটনাগুলি "সত্য" মেমরি ফাঁস নয় কারণ আশেপাশে সেই সমস্ত অবজেক্টের রেফারেন্স রয়েছে তবে প্রোগ্রামটি যদি আবার সেই উল্লেখগুলি আবার কখনও ব্যবহার না করে এবং এগুলি বাদ দেয় না তবে এটি সম্পূর্ণরূপে (এবং হিসাবে খারাপ) সত্য স্মৃতি ফাঁস "।
এহাবকোস্ট

@ নিকোলাস বাউসকেট: "মেমোরি ফুটো সত্যিই সত্যই সম্ভব" আপনাকে অনেক ধন্যবাদ +15 upvotes। খুশী হলাম। আমি এই সত্যটি তুলে
ধরার

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

... এবং PhantomReferenceযদি কোনও বস্তু এটির যত্নবান কাউকে না পাওয়া যায় তবে সিস্টেমে বিজ্ঞপ্তিগুলি (অনুরূপ মাধ্যমের মাধ্যমে ) সরবরাহ করতে হবে। WeakReferenceকিছুটা কাছাকাছি আসে, তবে এটি ব্যবহারের আগে অবশ্যই দৃ strong় রেফারেন্সে রূপান্তর করতে হবে; শক্তিশালী রেফারেন্স বিদ্যমান থাকাকালীন যদি কোনও জিসি চক্র ঘটে তবে লক্ষ্যটিকে কার্যকর বলে ধরে নেওয়া হবে।
সুপারক্যাট

এটি আমার মতে সঠিক উত্তর। আমরা বহু বছর আগে একটি সিমুলেশন লিখেছিলাম। কোনওভাবেই আমরা দুর্ঘটনাক্রমে আগের অবস্থার সাথে বর্তমান অবস্থার সাথে মেমরি ফাঁস তৈরি করেছি। একটি সময়সীমা থাকার কারণে আমরা কখনই মেমরি ফাঁস সমাধান করেনি তবে এটি নথিবদ্ধ করে একটি «বৈশিষ্ট্য made বানিয়েছি।
এলোমেলোভাবে

163

উত্তরটি পুরোপুরি নির্ভর করে যে সাক্ষাত্কারকারীর তারা কী জিজ্ঞাসা করেছিল।

অনুশীলনে জাভা ফুটা করা কি সম্ভব? অবশ্যই এটি, এবং অন্যান্য উত্তরগুলিতে প্রচুর উদাহরণ রয়েছে।

তবে একাধিক মেটা-প্রশ্ন রয়েছে যা জিজ্ঞাসা করা হতে পারে?

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

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

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


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

দয়া করে আমার প্রশ্নটি একবার দেখুন, ধন্যবাদ স্ট্যাকওভারফ্লো.com
ড্যানিয়েল নিউটাউন

130

আপনি জেডিবিসি না বুঝতে পারলে নীচে একটি দুর্দান্ত অর্থহীন উদাহরণ । বা অন্তত কিভাবে JDBC এর নিকট একজন বিকাশকারী আশা এ Connection, Statementএবং ResultSetতাদের খারিজ অথবা তাদের উল্লেখ হারানোর পরিবর্তে বাস্তবায়ন জানানোর আগে দৃষ্টান্ত finalize

void doWork()
{
   try
   {
       Connection conn = ConnectionFactory.getConnection();
       PreparedStatement stmt = conn.preparedStatement("some query"); // executes a valid query
       ResultSet rs = stmt.executeQuery();
       while(rs.hasNext())
       {
          ... process the result set
       }
   }
   catch(SQLException sqlEx)
   {
       log(sqlEx);
   }
}

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

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

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

অবজেক্ট চূড়ান্তকরণের সময় ব্যতিক্রমগুলির মুখোমুখি হওয়ার উপরের দৃশ্যটি অন্য একটি দৃশ্যের সাথে সম্পর্কিত যা সম্ভবত একটি স্মৃতি ফাঁস হতে পারে - অবজেক্টের পুনরুত্থান। অবজেক্টের পুনরুত্থান প্রায়শই অন্য বস্তু থেকে চূড়ান্ত হওয়া থেকে অবজেক্টের একটি শক্তিশালী রেফারেন্স তৈরি করে উদ্দেশ্যমূলকভাবে করা হয়। যখন অবজেক্টের পুনরুত্থানের অপব্যবহার করা হয় তখন এটি মেমরি ফাঁসের অন্যান্য উত্সগুলির সাথে মেমরির ফাঁস হতে পারে to

এমন আরও অনেকগুলি উদাহরণ রয়েছে যা আপনি জাঁকতে পারেন - পছন্দ করুন

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

98
আপনি সাধারণত মেমরি সীমাতে আঘাত করার আগে আপনি সর্বাধিক উন্মুক্ত সংযোগ সীমাতে পৌঁছে যাবেন। কেন জানি আমি আমাকে জিজ্ঞাসা করবেন না ...
হার্ডওয়্যারগুই

ওরাকল জেডিবিসি ড্রাইভার এটি করার জন্য কুখ্যাত।
চটচকি

@ হার্ডওয়ারগুই আমার Connection.closeসমস্ত এসকিউএল কলগুলির অবশেষে অবধি প্রবেশ না করা অবধি আমি এসকিউএল ডাটাবেসের সংযোগ সীমাটিকে অনেক হিট করেছি। অতিরিক্ত মজাদার জন্য আমি কিছু দীর্ঘ চলমান ওরাকল সঞ্চিত প্রক্রিয়া কল করেছিলাম যা জাভা সাইডে লক প্রয়োজন যা ডাটাবেসে খুব বেশি কল রোধ করতে পারে।
মাইকেল শপসিন

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

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

119

সম্ভাব্য মেমরি ফুটো এবং সম্ভবত কীভাবে এড়ানো যায় তার অন্যতম সহজ উদাহরণ হ'ল অ্যারেলিস্ট.রেমোভ (ইনট) এর বাস্তবায়ন:

public E remove(int index) {
    RangeCheck(index);

    modCount++;
    E oldValue = (E) elementData[index];

    int numMoved = size - index - 1;
    if (numMoved > 0)
        System.arraycopy(elementData, index + 1, elementData, index,
                numMoved);
    elementData[--size] = null; // (!) Let gc do its work

    return oldValue;
}

আপনি যদি এটি নিজে প্রয়োগ করে থাকেন তবে আপনি কী অ্যারে এলিমেন্টটি আর ব্যবহার করবেন না তা পরিষ্কার করার চিন্তা করতেন ( elementData[--size] = null)? এই রেফারেন্সটি একটি বিশাল অবজেক্টকে বাঁচিয়ে রাখতে পারে ...


5
আর এখানে স্মৃতি ফাঁস কোথায়?
আরডিএস

28
@ মানিক: আমি বোঝাতে চাইছি না যে এই কোডটি একটি মেমরি ফুটো দেখায়। আমি এটিকে উদ্ধৃত করে দেখিয়েছি যে কখনও কখনও দুর্ঘটনাজনিত অবজেক্টটি ধরে রাখা এড়াতে অ-স্পষ্ট কোড প্রয়োজন।
মেরিটন

রেঞ্জচেক (সূচক) কী; ?
Koray Tugay

6
জোশুয়া ব্লচ স্ট্যাকগুলির একটি সহজ প্রয়োগ দেখিয়ে কার্যকর জাভাতে এই উদাহরণ দিয়েছেন। খুব ভাল উত্তর।
ভাড়া

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

68

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


14
আমি বিশ্বাস করি না এটি একটি "ফুটো"। এটি একটি বাগ, এবং এটি প্রোগ্রাম এবং ভাষার নকশা দ্বারা। একটি ফুটো হ'ল কোনও বস্তু যা তার কোনও উল্লেখ ছাড়াই চারদিকে ঝুলছে ।
ব্যবহারকারী541686

29
@ মেহরদাদ: এটি কেবলমাত্র একটি সংকীর্ণ সংজ্ঞা যা সমস্ত ভাষায় পুরোপুরি প্রয়োগ হয় না। আমি যুক্তি দিয়েছি যে কোনও মেমরি ফাঁস প্রোগ্রামের দুর্বল ডিজাইনের কারণে একটি বাগ।
বিল

9
@ মেহরদাদ: ...then the question of "how do you create a memory leak in X?" becomes meaningless, since it's possible in any language. আপনি কীভাবে এই উপসংহারটি আঁকছেন তা আমি দেখতে পাচ্ছি না। যে কোনও সংজ্ঞায় জাভাতে মেমরি ফুটো তৈরির কয়েকটি উপায় রয়েছে। এটি অবশ্যই একটি বৈধ প্রশ্ন।
বিল করুন

7
@ 31eee384: যদি আপনার প্রোগ্রামটি এমন জিনিসগুলিকে মেমরিতে রাখে যা এটি কখনও ব্যবহার করতে পারে না, তবে প্রযুক্তিগতভাবে এটি মেমরি ফাঁস করে। আপনার বড় সমস্যা হওয়ার বিষয়টি সত্য যে এটি পরিবর্তন করে না।
বিল

8
@ 31eee384: আপনি যদি এমন কোনও সত্যের জন্য জানেন যে এটি হবে না তবে তা হতে পারে না। প্রোগ্রাম হিসাবে লিখিত, ডেটা অ্যাক্সেস করবে না।
বিল

51

আপনি sun.misc.Unsafe শ্রেণীর সাহায্যে মেমরি ফাঁস করতে সক্ষম । আসলে এই পরিষেবা শ্রেণিটি বিভিন্ন স্ট্যান্ডার্ড ক্লাসে ব্যবহৃত হয় (উদাহরণস্বরূপ জাভা.নিও ক্লাসে)। আপনি সরাসরি এই শ্রেণীর উদাহরণ তৈরি করতে পারবেন না , তবে আপনি এটি করতে প্রতিচ্ছবি ব্যবহার করতে পারেন

Eclipse IDE- এ কোডটি সংকলন করে না - কমান্ড ব্যবহার করে এটি javacসংকলন করুন (সংকলনের সময় আপনি সতর্কতা পাবেন)

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import sun.misc.Unsafe;


public class TestUnsafe {

    public static void main(String[] args) throws Exception{
        Class unsafeClass = Class.forName("sun.misc.Unsafe");
        Field f = unsafeClass.getDeclaredField("theUnsafe");
        f.setAccessible(true);
        Unsafe unsafe = (Unsafe) f.get(null);
        System.out.print("4..3..2..1...");
        try
        {
            for(;;)
                unsafe.allocateMemory(1024*1024);
        } catch(Error e) {
            System.out.println("Boom :)");
            e.printStackTrace();
        }
    }

}

1
বরাদ্দ মেমরি আবর্জনা সংগ্রাহকের জন্য অদৃশ্য
স্টেম

4
বরাদ্দকৃত মেমরিটি জাভা সম্পর্কিত নয়।
বেটসেস

এই সূর্য / ওরাকল জেভিএম নির্দিষ্ট? যেমন আইবিএম এ কাজ করবে?
বার্লিন ব্রাউন

2
মেমরিটি অবশ্যই "জাভার অন্তর্গত" নয়, অন্তত এই অর্থে যে i) এটি অন্য কারও কাছে উপলব্ধ নয়, ii) জাভা অ্যাপ্লিকেশনটি প্রস্থান করার পরে এটি সিস্টেমে ফিরে আসবে। এটি জেভিএমের ঠিক বাইরে।
মাইকেল অ্যান্ডারসন

3
এটি গ্রহণে নির্মিত হবে (কমপক্ষে সাম্প্রতিক সংস্করণগুলিতে) তবে আপনাকে সংকলক সেটিংস পরিবর্তন করতে হবে: উইন্ডোতে> পছন্দসমূহ> জাভা> কম্পাইলার> ত্রুটি / সতর্কতা> অবজ্ঞাত এবং সীমাবদ্ধ এপিআই সেট সেট নিষিদ্ধ রেফারেন্স (অ্যাক্সেসের নিয়ম) থেকে "সতর্কতা" "।
মাইকেল অ্যান্ডারসন

43

আমি আমার উত্তরটি এখানে থেকে অনুলিপি করতে পারি: জাভাতে মেমরি ফাঁস হওয়ার সবচেয়ে সহজ উপায়?

"কম্পিউটার বিজ্ঞানে (বা এই প্রসঙ্গে ফাঁস) একটি মেমরি ফাঁস হয় যখন কোনও কম্পিউটার প্রোগ্রাম মেমরি গ্রহণ করে তবে অপারেটিং সিস্টেমে এটি পুনরায় মুক্তি দিতে অক্ষম হয়" " (উইকিপিডিয়া)

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

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

দীর্ঘ উত্তরটি: আপনি জেএনআই ব্যবহার করে জাভাটির জন্য একটি লাইব্রেরি লিখে মেমরি ফাঁস পেতে পারেন, যার ম্যানুয়াল মেমরি পরিচালনা থাকতে পারে এবং মেমরি ফাঁস থাকতে পারে। আপনি যদি এই লাইব্রেরিটি কল করেন তবে আপনার জাভা প্রক্রিয়াটি মেমরি ফাঁস করবে। অথবা, আপনার জেভিএম-তে বাগ থাকতে পারে, যাতে জেভিএম স্মৃতি হারিয়ে ফেলে। সম্ভবত জেভিএম-তে বাগ রয়েছে, এমনকী কিছু জ্ঞাত থাকতে পারে যেহেতু আবর্জনা সংগ্রহ করা তুচ্ছ নয়, তবে এটি এখনও একটি বাগ। ডিজাইন দ্বারা এটি সম্ভব নয়। আপনি এমন কিছু জাভা কোড চাইছেন যা এইরকম বাগ দ্বারা প্রভাবিত। দুঃখিত, আমি একটি জানি না এবং এটি পরবর্তী জাভা সংস্করণে যাইহোক, সম্ভবত এটি কোনও বাগ নাও হতে পারে।


12
এটি মেমরি ফাঁসের একটি অত্যন্ত সীমাবদ্ধ (এবং খুব দরকারী নয়) সংজ্ঞা। ব্যবহারিক উদ্দেশ্যগুলির জন্য একমাত্র সংজ্ঞা যা "মেমরি ফুটো এমন কোনও শর্ত যা প্রোগ্রামের দ্বারা বরাদ্দকৃত মেমোরিটিকে ধরে রাখা ডেটার পরে এটির আর প্রয়োজন হয় না" "
ম্যাসন হুইলারের

1
উল্লিখিত অ্যাকনরাডের উত্তর মুছে ফেলা হয়েছে?
টোমা জ্যাটো - মনিকা

1
@ টম্যাজাটো: না, তা নয়। আমি এখন লিঙ্ক করতে উপরের রেফারেন্সটি ঘুরিয়েছি, যাতে আপনি এটি সহজেই খুঁজে পেতে পারেন।
ইয়াঙ্কি

বস্তুর পুনরুত্থান কি? একজন ধ্বংসকারীকে কতবার কল করা হয়? এই প্রশ্নগুলি কীভাবে এই উত্তরটিকে অস্বীকার করবে?
অটিস্টিক

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

39

Http://wiki.eclipse.org/Performance_Bloopers#String.substring.28.29- এর মাধ্যমে এখানে একটি সরল / অশুভ ।

public class StringLeaker
{
    private final String muchSmallerString;

    public StringLeaker()
    {
        // Imagine the whole Declaration of Independence here
        String veryLongString = "We hold these truths to be self-evident...";

        // The substring here maintains a reference to the internal char[]
        // representation of the original string.
        this.muchSmallerString = veryLongString.substring(0, 1);
    }
}

যেহেতু সাবস্ট্রিং মূলটির অভ্যন্তরীণ প্রতিনিধিত্বকে বোঝায়, দীর্ঘতর স্ট্রিং, আসল স্মৃতিতে থাকে। সুতরাং, যতক্ষণ না আপনি স্ট্রিংলিকার প্লে করছেন, আপনার স্মৃতিতেও পুরো আসল স্ট্রিং রয়েছে, এমনকি আপনি যদি মনে করেন যে আপনি কেবল একটি একক চরিত্রের স্ট্রিং ধরে আছেন।

মূল স্ট্রিংয়ের সাথে অযাচিত রেফারেন্সটি সংরক্ষণ না করার উপায় হ'ল এইরকম কিছু করা:

...
this.muchSmallerString = new String(veryLongString.substring(0, 1));
...

খারাপ যুক্ত করার জন্য, আপনি .intern()সাবস্ট্রিংও করতে পারেন :

...
this.muchSmallerString = veryLongString.substring(0, 1).intern();
...

এটি করার ফলে স্ট্রিংলিকার উদাহরণটি বাতিল করার পরেও মূল লং স্ট্রিং এবং উত্পন্ন সাবস্ট্রিং উভয়ই মেমোরিতে থাকবে।


4
আমি যে একটি মেমরি লিক, কল না কোনটাই । যখন মুক্ত muchSmallerStringহয় (কারণ StringLeakerবস্তুটি ধ্বংস হয়ে যায়), দীর্ঘ স্ট্রিংটিও মুক্ত করা হবে। আমি যাকে মেমরি ফাঁস বলি তা হ'ল মেমরি যা জেভিএম-এর এই দৃষ্টিতে কখনই মুক্ত করা যায় না। যাইহোক, যদি আপনি নিজেকে দেখানো হয়েছে কিভাবে মেমরির মুক্ত করতে: this.muchSmallerString=new String(this.muchSmallerString)। একটি সত্যিকারের মেমরি ফুটো হওয়ার সাথে, আপনার করার মতো কিছুই নেই।
আরডিএস

2
@ আরডিএস, এটি একটি ন্যায্য বিষয়। নন- internকেসটি "মেমরি ফাঁস" এর চেয়ে "মেমোরি অবাক" হতে পারে। .intern()স্ট্রিংগুলিকে আইএনਗ দিলে অবশ্যই এমন একটি পরিস্থিতি তৈরি হয় যেখানে দীর্ঘ স্ট্রিংয়ের রেফারেন্সটি সংরক্ষিত থাকে এবং মুক্ত করা যায় না।
জন চেম্বারস

15
পদ্ধতিটি স্ট্রিংং ()
জাভা

এমনকি আপনার নিজেরাই স্ট্রিং () নিজে করার দরকার নেই: বিশাল ইনপুটটির একটি ছোট অংশের সাথে মেলে ধরতে একটি রেইগেক্স ম্যাচার ব্যবহার করুন এবং দীর্ঘ সময় ধরে "নিষ্কাশিত" স্ট্রিংটি বহন করুন। বিশাল ইনপুটটি জাভা 6 অবধি বেঁচে থাকে
বনানুইজন

37

জিইউআই কোডে এর একটি সাধারণ উদাহরণ হ'ল যখন কোনও উইজেট / উপাদান তৈরি করা হয় এবং শ্রোতাকে কিছু স্ট্যাটিক / অ্যাপ্লিকেশন স্কোপড অবজেক্টে যুক্ত করা হয় এবং তারপরে উইজেটটি ধ্বংস হয়ে যায় তখন শ্রোতাকে সরিয়ে না দেওয়া হয়। আপনি কেবল একটি মেমরি ফুটোই পান না, পারফরম্যান্সেও হিট হন যখন আপনি আগুনের ঘটনাগুলি যা শুনছেন তা আপনার সমস্ত পুরানো শ্রোতাদেরও বলা হয়।


1
অ্যান্ড্রয়েড প্ল্যাটফর্ম একটি দৃশ্যের স্থিতিশীল ক্ষেত্রে বিটম্যাপকে ক্যাশে করে তৈরি মেমরি ফুটোটির উদাহরণ দেয় ।
আরডিএস

36

যে কোনও সার্লেট পাত্রে চলমান কোনও ওয়েব অ্যাপ্লিকেশন নিন (টমক্যাট, জেটি, গ্লাসফিশ, যাই হোক না কেন ...)। অ্যাপ্লিকেশনটি পর পর 10 বা 20 বার পুনরায় চালিত করুন (এটি সার্ভারের অটোডেপ্লাই ডিরেক্টরিতে কেবল ওয়ার স্পর্শ করার পক্ষে যথেষ্ট।

প্রকৃতপক্ষে যদি কেউ এটি পরীক্ষা না করে থাকে তবে সম্ভাবনা বেশি থাকে যে আপনি বেশ কয়েকবার পুনর্নির্মাণের পরে একটি আউটআফমিউরিওর পেয়ে যাবেন, কারণ অ্যাপ্লিকেশনটি নিজের পরে পরিষ্কার করার যত্ন নেয়নি। এমনকি আপনি এই পরীক্ষার মাধ্যমে আপনার সার্ভারে একটি বাগ খুঁজে পেতে পারেন।

সমস্যাটি হল, ধারকটির আজীবন আপনার আবেদনের আজীবনের চেয়ে দীর্ঘ। আপনাকে অবশ্যই নিশ্চিত করতে হবে যে আপনার অ্যাপ্লিকেশনটির ধারকগুলিতে বা ক্লাসগুলির মধ্যে থাকা সমস্ত উল্লেখগুলি আবর্জনা সংগ্রহ করতে পারে।

যদি আপনার ওয়েব অ্যাপ্লিকেশনটির অপ্রয়োজনীয় কর্মসংস্থানের মধ্যে কেবলমাত্র একটি রেফারেন্স থাকে তবে সংশ্লিষ্ট শ্রেণি লোডার এবং ফলস্বরূপ আপনার ওয়েব অ্যাপ্লিকেশনের সমস্ত শ্রেণি আবর্জনা সংগ্রহ করা যাবে না।

আপনার অ্যাপ্লিকেশন দ্বারা সূচিত থ্রেডস, থ্রেডলোকাল ভেরিয়েবল, লগিং অ্যাপেন্ডারগণ শ্রেণি লোডার ফাঁস হওয়ার জন্য কিছু সাধারণ সন্দেহভাজন।


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

35

জেএনআই এর মাধ্যমে বাহ্যিক নেটিভ কোড ব্যবহার করে?

খাঁটি জাভা দিয়ে এটি প্রায় অসম্ভব।

তবে এটি একটি "স্ট্যান্ডার্ড" ধরণের মেমরি ফাঁস, যখন আপনি আর মেমরি অ্যাক্সেস করতে পারবেন না তবে এটি এখনও অ্যাপ্লিকেশনটির মালিকানাধীন। পরিবর্তে অব্যবহৃত অবজেক্টের জন্য রেফারেন্স রাখতে পারেন, বা স্ট্রিমগুলি পরে বন্ধ না করেই খুলতে পারেন।


22
এটি "মেমরি ফাঁস" এর সংজ্ঞা উপর নির্ভর করে। যদি "স্মৃতি যা ধরে রেখেছে, তবে আর প্রয়োজন হয় না", তবে জাভাতে এটি করা সহজ। যদি এটি "মেমরি যা বরাদ্দ করা হয় তবে কোডের মাধ্যমে একেবারেই অ্যাক্সেসযোগ্য নয়", তবে এটি কিছুটা শক্ত হয়ে যায়।
জোছিম সউর

@ জোয়াচিম সাউর - আমার অর্থ দ্বিতীয় প্রকার। প্রথমটি তৈরি করা মোটামুটি সহজ :)
রোগাচ

6
"খাঁটি জাভা দিয়ে এটি প্রায় অসম্ভব।" ভাল, আমার অভিজ্ঞতা অন্যটি বিশেষত যখন এখানে লোকজনদের সম্পর্কে অবগত নয় এমন লোকদের ক্যাশে প্রয়োগ করার বিষয়টি আসে।
ফ্যাবিয়ান বার্নি

4
@Rogach আছে: মূলত মানুষ বিভিন্ন উত্তরের উপর +400 upvotes +10 000 প্রতিনিধির দেখাচ্ছে যে উভয় ক্ষেত্রেই সঙ্গে আছে জোয়াকিম সয়ার মন্তব্য এটা খুবই সম্ভব। সুতরাং আপনার "প্রায় অসম্ভব" কোনও ধারণা রাখে না।
SyntaxT3rr0r

32

পারমজেন এবং এক্সএমএল পার্সিংয়ের সাথে আমার একবার "মেমরি ফুটো" হয়েছে। তুলনাটি দ্রুততর করার জন্য, আমরা যে এক্সএমএল পার্সারটি ব্যবহার করেছি (তা স্মরণ করতে পারি না যে এটি কোনটি ছিল) ট্যাগ নামগুলিতে একটি স্ট্রিং.ইনটার্ন () করেছে। আমাদের গ্রাহকের একের কাছে এক্সএমএল বৈশিষ্ট্য বা পাঠ্যে না হয়ে ডেটা মান সংরক্ষণ করার দুর্দান্ত ধারণা ছিল, তবে আমাদের কাছে একটি নথি ছিল:

<data>
   <1>bla</1>
   <2>foo</>
   ...
</data>

প্রকৃতপক্ষে, তারা সংখ্যাগুলি ব্যবহার করেনি তবে দীর্ঘতর পাঠ্য আইডি (প্রায় 20 টি অক্ষর), যা অনন্য ছিল এবং দিনে 10-15 মিলিয়ন হারে আসে। এটি দিনে 200 এমবি জঞ্জাল করে তোলে, যা আর কখনও প্রয়োজন হয় না এবং কখনও জিসিড হয় না (যেহেতু এটি পারমজেনে রয়েছে)। আমাদের 512 এমবি সেট করা হয়েছে, সুতরাং স্মৃতি বহির্ভূত ব্যতিক্রম (OOM) আসতে প্রায় দুই দিন সময় লাগল ...


4
কেবলমাত্র আপনার উদাহরণ কোডটি নিটপিক করার জন্য: আমি মনে করি এক্সএমএলে উপাদান নাম হিসাবে সংখ্যাগুলি (বা সংখ্যা দিয়ে শুরু হওয়া স্ট্রিং) অনুমোদিত নয়।
পাওলো ইবারম্যান

নোট করুন যে এটি আর জেডিকে 7+ এর ক্ষেত্রে আর সত্য নয়, যেখানে স্ট্রিং ইন্টার্নিংয়ের স্তূপ ঘটে। বিস্তারিত নিবন্ধের জন্য এই নিবন্ধটি দেখুন: java-performance.info/string-intern-in-java-6-7-8
জেমিসেরেজ

24

একটি স্মৃতি ফাঁস কি:

  • এটি কোনও বাগ বা খারাপ নকশার কারণে ঘটে caused
  • এটি স্মৃতির অপচয়।
  • সময়ের সাথে সাথে এটি আরও খারাপ হয়।
  • আবর্জনা সংগ্রহকারী এটি পরিষ্কার করতে পারবেন না।

সাধারণ উদাহরণ:

বিষয়বস্তুগুলির একটি ক্যাশে জিনিস জগাখিচুড়ি করার একটি ভাল সূচনা পয়েন্ট।

private static final Map<String, Info> myCache = new HashMap<>();

public void getInfo(String key)
{
    // uses cache
    Info info = myCache.get(key);
    if (info != null) return info;

    // if it's not in cache, then fetch it from the database
    info = Database.fetch(key);
    if (info == null) return null;

    // and store it in the cache
    myCache.put(key, info);
    return info;
}

আপনার ক্যাশে বৃদ্ধি এবং বড় হয়। এবং খুব শীঘ্রই পুরো ডাটাবেস মেমরি চুষতে হবে। একটি ভাল ডিজাইন একটি LRUMap ব্যবহার করে (কেবল সম্প্রতি ব্যবহৃত জিনিসগুলিকে ক্যাশে রাখে)।

অবশ্যই, আপনি জিনিসগুলি আরও জটিল করে তুলতে পারেন:

  • থ্রেডলোকাল ব্যবহার করে নির্মাণ ।
  • আরও জটিল রেফারেন্স ট্রি যুক্ত করা হচ্ছে
  • বা তৃতীয় পক্ষের গ্রন্থাগারগুলির কারণে ফাঁস ।

যা প্রায়শই ঘটে:

যদি এই তথ্য অবজেক্টে অন্যান্য অবজেক্টের রেফারেন্স থাকে তবে এর সাথে আবার অন্য অবজেক্টের রেফারেন্স রয়েছে। একটি উপায়ে আপনি এটিকে একরকমের মেমরি ফাঁস, (খারাপ ডিজাইনের কারণে) বিবেচনা করতে পারেন।


22

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

public class Example1 {
  public Example2 getNewExample2() {
    return this.new Example2();
  }
  public class Example2 {
    public Example2() {}
  }
}

এখন আপনি যদি উদাহরণ 1 এ কল করুন এবং একটি উদাহরণ 2 ছাড়ুন উদাহরণ 1, আপনার কাছে সহজাতভাবে এখনও উদাহরণ 1 অবজেক্টের লিঙ্ক থাকবে।

public class Referencer {
  public static Example2 GetAnExample2() {
    Example1 ex = new Example1();
    return ex.getNewExample2();
  }

  public static void main(String[] args) {
    Example2 ex = Referencer.GetAnExample2();
    // As long as ex is reachable; Example1 will always remain in memory.
  }
}

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


2
অভ্যন্তরীণ ক্লাসগুলি খুব কমই একটি সমস্যা। এগুলি একটি সোজাসাপ্টা কেস এবং এটি সনাক্ত করা খুব সহজ। গুজবটিও কেবল একটি গুজব।
9:51

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

22

লগ 4 জে করে সম্প্রতি আমি একটি মেমরি ফাঁস হওয়ার পরিস্থিতির মুখোমুখি হয়েছি।

লগ 4 জে নেস্টেড ডায়াগনস্টিক কনটেক্সট (এনডিসি) নামে পরিচিত এই প্রক্রিয়াটি রয়েছে যা বিভিন্ন উত্স থেকে আন্তঃবাহিত লগ আউটপুটকে আলাদা করার একটি উপকরণ। এনডিসি যে গ্রানুলারিটিতে কাজ করে তা হ'ল থ্রেড, তাই এটি লগ আউটপুটগুলি পৃথকভাবে বিভিন্ন থ্রেড থেকে পৃথক করে।

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

pubclic class RequestProcessor {
    private static final Logger logger = Logger.getLogger(RequestProcessor.class);
    public void doSomething()  {
        ....
        final List<String> hugeList = new ArrayList<String>(10000);
        new Thread() {
           public void run() {
               logger.info("Child thread spawned")
               for(String s:hugeList) {
                   ....
               }
           }
        }.start();
    }
}    

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


যে স্তন্যপান। আপনার এই লগিং লাইব্রেরিটি পরীক্ষা করা উচিত যা কোনও ফাইল লগ করার সময় জিরো মেমরির বরাদ্দ করে: mentolog.soliverajr.com
ট্রেডারজয়ে শিকাগো

+1 আপনি কি জানেন যে এসডিএফ 4 জে / লগব্যাক (একই লেখকের উত্তরসূরি পণ্য) তে এমডিসির সাথে একই রকম সমস্যা আছে কিনা? আমি উত্সটিতে একটি গভীর ডুব দিতে চলেছি তবে প্রথমে চেক করতে চেয়েছি। যেভাবেই হোক, এই পোস্ট করার জন্য ধন্যবাদ।
স্পার্ক_স্প্রেড 21

20

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

class A {
    B bRef;
}

class B {
    A aRef;
}

public class Main {
    public static void main(String args[]) {
        A myA = new A();
        B myB = new B();
        myA.bRef = myB;
        myB.aRef = myA;
        myA=null;
        myB=null;
        /* at this point, there is no access to the myA and myB objects, */
        /* even though both objects still have active references. */
    } /* main */
}

তারপরে আপনি ব্যাখ্যা করতে পারেন যে রেফারেন্স গণনা সহ উপরের কোডটি মেমরি ফাঁস করবে। তবে বেশিরভাগ আধুনিক জেভিএমরা আর গণনা গণনা আর ব্যবহার করে না, বেশিরভাগ সুইপ আবর্জনা সংগ্রহকারী ব্যবহার করে, যা প্রকৃতপক্ষে এই স্মৃতিটি সংগ্রহ করবে।

এরপরে আপনি কোনও অবজেক্ট তৈরির ব্যাখ্যা করতে পারেন যার অন্তর্নিহিত দেশীয় উত্স রয়েছে, এর মতো:

public class Main {
    public static void main(String args[]) {
        Socket s = new Socket(InetAddress.getByName("google.com"),80);
        s=null;
        /* at this point, because you didn't close the socket properly, */
        /* you have a leak of a native descriptor, which uses memory. */
    }
}

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

দিনের শেষে, একটি আধুনিক জেভিএম সহ, আপনাকে কিছু জাভা কোড লিখতে হবে যা জেভিএমের সচেতনতার স্বাভাবিক ক্ষেত্রের বাইরে একটি নেটিভ রিসোর্স বরাদ্দ করে।


19

প্রত্যেকে সর্বদা নেটিভ কোডের রুটটি ভুলে যায়। এখানে ফাঁসের একটি সহজ সূত্র:

  1. দেশীয় পদ্ধতি ঘোষণা করুন।
  2. নেটিভ পদ্ধতিতে কল করুন malloc। ফোন করবেন না free
  3. নেটিভ পদ্ধতিতে কল করুন।

মনে রাখবেন, নেটিভ কোডে মেমরির বরাদ্দগুলি JVM হিপ থেকে আসে।


1
একটি সত্য বিবরণ উপর ভিত্তি করে।
রেজি

18

একটি স্থিতিশীল মানচিত্র তৈরি করুন এবং এতে কঠোর উল্লেখ যুক্ত করুন। এগুলি কখনই জিসিডি হবে না।

public class Leaker {
    private static final Map<String, Object> CACHE = new HashMap<String, Object>();

    // Keep adding until failure.
    public static void addToCache(String key, Object value) { Leaker.CACHE.put(key, value); }
}

87
কেমন যেন ফুটো? এটি আপনি যা করতে বলছেন ঠিক তা করছে। যদি এটি ফাঁস হয় তবে যে কোনও জায়গায় অবজেক্ট তৈরি করা এবং সংরক্ষণ করা এটি ফাঁস।
ফালমারি

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

3
আমার বক্তব্যটি হ'ল যে কেউ অবজেক্ট তৈরি করে চলেছে, সম্ভবত এগুলি ক্যাশে রাখে, যদি তারা সতর্ক না হয় তবে তারা OOM এর ত্রুটিটি শেষ করতে পারে।
duffymo

8
@ ডিফাইমো: তবে প্রশ্নটি যা বলছিল তা আসলে এটি নয়। এটি কেবল আপনার সমস্ত স্মৃতি ব্যবহার করে কিছু করার নেই।
ফালমারি

3
একেবারে অবৈধ। আপনি কেবল মানচিত্রের সংগ্রহের মধ্যে একগুচ্ছ অবজেক্ট সংগ্রহ করছেন। তাদের রেফারেন্সগুলি রাখা হবে কারণ মানচিত্রটি তাদের ধারণ করে।
গির্জ্যাব্রাহাম

16

শ্রেণীর চূড়ান্তকরণ পদ্ধতিতে কোনও শ্রেণীর একটি নতুন উদাহরণ তৈরি করে আপনি চলন্ত মেমরি ফাঁস তৈরি করতে পারেন। চূড়ান্তকরণকারীর একাধিক উদাহরণ তৈরি হলে বোনাস পয়েন্ট। এখানে একটি সাধারণ প্রোগ্রাম যা আপনার গাদা আকারের উপর নির্ভর করে কয়েক সেকেন্ড এবং কয়েক মিনিটের মধ্যে পুরো স্তূপটি ফাঁস করে দেয়:

class Leakee {
    public void check() {
        if (depth > 2) {
            Leaker.done();
        }
    }
    private int depth;
    public Leakee(int d) {
        depth = d;
    }
    protected void finalize() {
        new Leakee(depth + 1).check();
        new Leakee(depth + 1).check();
    }
}

public class Leaker {
    private static boolean makeMore = true;
    public static void done() {
        makeMore = false;
    }
    public static void main(String[] args) throws InterruptedException {
        // make a bunch of them until the garbage collector gets active
        while (makeMore) {
            new Leakee(0).check();
        }
        // sit back and watch the finalizers chew through memory
        while (true) {
            Thread.sleep(1000);
            System.out.println("memory=" +
                    Runtime.getRuntime().freeMemory() + " / " +
                    Runtime.getRuntime().totalMemory());
        }
    }
}

15

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


10
এটি অসত্য। finalize()ডাকা হবে না তবে একবারে আরও রেফারেন্স পাওয়া যাবে না বলে এই বস্তুটি সংগ্রহ করা হবে। আবর্জনা সংগ্রহকারীকে 'বলাও হয় না'।
বেটসেস

1
এই উত্তরটি বিভ্রান্তিমূলক, finalize()পদ্ধতিটিকে কেবল একবার জেভিএম দ্বারা ডাকা যেতে পারে, তবে এর অর্থ এই নয় যে বস্তুটি পুনরুত্থিত করা হয় এবং তারপরে আবার অবজ্ঞা করা হয় তবে এটি পুনরায় আবর্জনা সংগ্রহ করা যাবে না। যদি পদ্ধতিতে রিসোর্স ক্লোজিং কোড থাকে finalize()তবে এই কোডটি আবার চলবে না, এটি মেমরি ফাঁস হতে পারে।
টম ক্যামম্যান

15

আমি সম্প্রতি আরও সূক্ষ্ম ধরণের রিসোর্স লিকটি পেয়েছি। আমরা শ্রেণি লোডার এর getResourceAsStream এর মাধ্যমে সংস্থানগুলি খুলি এবং এটি ঘটেছিল যে ইনপুট স্ট্রিম হ্যান্ডলগুলি বন্ধ ছিল না।

আহ, আপনি বলতে পারেন, কি বোকা।

আচ্ছা, এটিকে আকর্ষণীয় করে তোলে: জেভিএমের গাদা না থেকে আপনি অন্তর্নিহিত প্রক্রিয়াটির হিপ মেমরি ফাঁস করতে পারেন।

আপনার যা দরকার তা হ'ল একটি জার ফাইল যা ভিতরে জাভা কোড থেকে রেফারেন্স করা যায় inside বড় জার ফাইলটি, দ্রুত মেমরি বরাদ্দ হয়ে যায়।

আপনি নিম্নলিখিত শ্রেণীর সাহায্যে সহজেই এই জাতীয় জার তৈরি করতে পারেন:

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class BigJarCreator {
    public static void main(String[] args) throws IOException {
        ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(new File("big.jar")));
        zos.putNextEntry(new ZipEntry("resource.txt"));
        zos.write("not too much in here".getBytes());
        zos.closeEntry();
        zos.putNextEntry(new ZipEntry("largeFile.out"));
        for (int i=0 ; i<10000000 ; i++) {
            zos.write((int) (Math.round(Math.random()*100)+20));
        }
        zos.closeEntry();
        zos.close();
    }
}

বিগজারক্রিটর.জাভা নামে একটি ফাইলের মধ্যে কেবল পেস্ট করুন, এটি কমান্ড লাইন থেকে সংকলন করুন এবং চালনা করুন:

javac BigJarCreator.java
java -cp . BigJarCreator

এবং দেখুন: আপনি ভিতরে দুটি ফাইল সহ আপনার বর্তমান ওয়ার্কিং ডিরেক্টরিতে একটি জার সংরক্ষণাগার খুঁজে পান।

আসুন একটি দ্বিতীয় শ্রেণি তৈরি করুন:

public class MemLeak {
    public static void main(String[] args) throws InterruptedException {
        int ITERATIONS=100000;
        for (int i=0 ; i<ITERATIONS ; i++) {
            MemLeak.class.getClassLoader().getResourceAsStream("resource.txt");
        }
        System.out.println("finished creation of streams, now waiting to be killed");

        Thread.sleep(Long.MAX_VALUE);
    }

}

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

যদি আপনার সন্দেহ হয় তবে উপরের ক্লাসটি সংকলন করে শুরু করার চেষ্টা করুন, তবে একটি শালীন গাদা আকার (2 এমবি) চয়ন করতে ভুলবেন না:

javac MemLeak.java
java -Xmx2m -classpath .:big.jar MemLeak

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

আপনি যদি অ্যাপ্লিকেশনটি নিরাপদে খেলতে চান তবে ইনপুট স্ট্রিমটি যেখানে তৈরি হয়েছে ঠিক সেখানেই বন্ধ করুন:

MemLeak.class.getClassLoader().getResourceAsStream("resource.txt").close();

এবং আপনার প্রক্রিয়া পুনরাবৃত্তি গণনার চেয়ে পৃথক 35 এমবি ছাড়িয়ে যাবে না।

বেশ সহজ এবং অবাক।


14

যেহেতু অনেক লোক পরামর্শ দিয়েছে, রিসোর্স লিকগুলি কারণ করা মোটামুটি সহজ - জেডিবিসি উদাহরণগুলির মতো। আসল মেমোরি ফাঁস কিছুটা শক্ত - বিশেষত যদি আপনি JVM এর ভাঙা বিটের উপর নির্ভর না করে থাকেন এটি করার জন্য ...

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

যদিও একটি উপায় কাজ করত - এবং আমি জানি না এটি এখনও হয় কিনা - একটি তিন-গভীর বিজ্ঞপ্তি শৃঙ্খল আছে। অবজেক্ট এ-তে যেমন অবজেক্ট বি-তে একটি রেফারেন্স রয়েছে, অবজেক্ট বি-তে অবজেক্ট সি-তে একটি রেফারেন্স রয়েছে এবং অবজেক্ট সি-তে অবজেক্ট-এ-তে একটি রেফারেন্স রয়েছে। জিসি এতটা চালাক ছিল যে একটি দুটি গভীর শৃঙ্খল - এ <--> বি হিসাবে - যদি A এবং B অন্য কোনও কিছুর দ্বারা অ্যাক্সেসযোগ্য না হয় তবে সুরক্ষিতভাবে সংগ্রহ করা যেতে পারে, তবে ত্রি-মুখী চেইনটি পরিচালনা করতে পারে না ...


7
কিছুদিন হয়ে ওঠেনি। আধুনিক জিসিরা বিজ্ঞপ্তি সংক্রান্ত রেফারেন্সগুলি পরিচালনা করতে জানেন know
Assylias

13

সম্ভাব্য বিশাল মেমরি তথ্য ফাঁসের তৈরি করতে আরেকটি উপায় উল্লেখ রাখা হয় Map.Entry<K,V>একটি এর TreeMap

কেন এটি কেবলমাত্র ক্ষেত্রে প্রযোজ্য তা নির্ধারণ করা শক্ত TreeMap, তবে বাস্তবায়নটি দেখে কারণটি হতে পারে: TreeMap.Entryস্টোরগুলি তার ভাইবোনদের জন্য রেফারেন্স দেয়, সুতরাং যদি কোনও TreeMapসংগ্রহ করার জন্য প্রস্তুত থাকে তবে অন্য কোনও শ্রেণীর যে কোনও একটির রেফারেন্স রয়েছে এটির Map.Entryপরে পুরো মানচিত্রটি স্মৃতিতে ধরে রাখা হবে।


বাস্তব জীবনের দৃশ্য:

একটি ডিবি ক্যোয়ারী থাকার কথা কল্পনা করুন যা একটি বড় TreeMapডেটা কাঠামোকে দেয়। TreeMapউপাদান সন্নিবেশ ক্রম বজায় রাখার সাথে সাথে লোকেরা সাধারণত ব্যবহার করে ।

public static Map<String, Integer> pseudoQueryDatabase();

যদি ক্যোয়ারিকে প্রচুর বার বলা হয় এবং প্রতিটি প্রশ্নের জন্য (সুতরাং, প্রত্যেকে Mapপ্রত্যাবর্তিত হয়ে) আপনি Entryকোথাও সংরক্ষণ করেন , স্মৃতিটি ক্রমাগত বাড়তে থাকবে।

নিম্নলিখিত র‌্যাপার শ্রেণি বিবেচনা করুন:

class EntryHolder {
    Map.Entry<String, Integer> entry;

    EntryHolder(Map.Entry<String, Integer> entry) {
        this.entry = entry;
    }
}

অ্যাপ্লিকেশন:

public class LeakTest {

    private final List<EntryHolder> holdersCache = new ArrayList<>();
    private static final int MAP_SIZE = 100_000;

    public void run() {
        // create 500 entries each holding a reference to an Entry of a TreeMap
        IntStream.range(0, 500).forEach(value -> {
            // create map
            final Map<String, Integer> map = pseudoQueryDatabase();

            final int index = new Random().nextInt(MAP_SIZE);

            // get random entry from map
            for (Map.Entry<String, Integer> entry : map.entrySet()) {
                if (entry.getValue().equals(index)) {
                    holdersCache.add(new EntryHolder(entry));
                    break;
                }
            }
            // to observe behavior in visualvm
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

    }

    public static Map<String, Integer> pseudoQueryDatabase() {
        final Map<String, Integer> map = new TreeMap<>();
        IntStream.range(0, MAP_SIZE).forEach(i -> map.put(String.valueOf(i), i));
        return map;
    }

    public static void main(String[] args) throws Exception {
        new LeakTest().run();
    }
}

প্রতিটি pseudoQueryDatabase()কল করার পরে , mapউদাহরণগুলি সংগ্রহের জন্য প্রস্তুত হওয়া উচিত, তবে এটি ঘটবে না, কারণ কমপক্ষে একটি Entryঅন্য কোথাও সঞ্চিত রয়েছে।

আপনার jvmসেটিংসের উপর নির্ভর করে এ-এর কারণে প্রাথমিক পর্যায়ে অ্যাপ্লিকেশনটি ক্রাশ হতে পারে OutOfMemoryError

আপনি এই visualvmগ্রাফ থেকে দেখতে পারেন কীভাবে স্মৃতিশক্তি বাড়তে থাকে।

মেমরি ডাম্প - ট্রি ম্যাপ

হ্যাশড ডেটা স্ট্রাকচার ( HashMap) এর সাথেও এটি ঘটে না ।

এটি ব্যবহার করার সময় এই গ্রাফটি HashMap

মেমরি ডাম্প - হ্যাশম্যাপ

সমাধান? এটিকে সংরক্ষণ না করে সরাসরি কী / মানটি (যেমন আপনি সম্ভবত ইতিমধ্যে করেছেন) সংরক্ষণ করুন Map.Entry


আমি এখানে আরও বিস্তৃত একটি মানদণ্ড লিখেছি ।


11

থ্রেডগুলি সমাপ্ত না হওয়া পর্যন্ত সংগ্রহ করা হয় না। তারা আবর্জনা সংগ্রহের শিকড় হিসাবে কাজ করে । এগুলি হ'ল কয়েকটি বস্তুর মধ্যে একটি যা তাদের সম্পর্কে ভুলে যাওয়া বা তাদের উল্লেখগুলি সাফ করার মাধ্যমে পুনরুদ্ধার করা হবে না।

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

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

খেলনার উদাহরণ হিসাবে:

static void leakMe(final Object object) {
    new Thread() {
        public void run() {
            Object o = object;
            for (;;) {
                try {
                    sleep(Long.MAX_VALUE);
                } catch (InterruptedException e) {}
            }
        }
    }.start();
}

System.gc()আপনার পছন্দ মতো সকলকে কল করুন , তবে যে বস্তুটি পাস করেছে leakMeতা কখনও মরে না।

(* সম্পাদিত *)


1
@ স্পিডি কিছুই "আটকে" নেই। কল করার পদ্ধতিটি তাত্ক্ষণিকভাবে ফিরে আসে এবং উত্তীর্ণ বস্তুটি পুনরুদ্ধার করা হবে না। এটি অবশ্যই ফুটো ak
বোয়ান

1
আপনার প্রোগ্রামটির আজীবন আপনার কাছে একটি চলমান থ্রেড থাকবে (বা ঘুমাও, যাই হোক না কেন)। এটি আমার কাছে ফাঁস হিসাবে গণ্য হয় না। পাশাপাশি একটি পুল কোনও ফাঁস হিসাবে গণ্য হয় না, এমনকি যদি আপনি এটি পুরোপুরি ব্যবহার না করেন।
স্পাইডি

1
@ স্পিডি "আপনার প্রোগ্রামের আজীবন আপনার কাছে একটি জিনিস থাকবে That এটি আমার কাছে ফাঁস হিসাবে গণ্য হবে না।" আপনি নিজে শুনছেন?
বোয়ান

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

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

10

আমি মনে করি যে বৈধ উদাহরণ থ্রেডলোকাল ভেরিয়েবল এমন পরিবেশে ব্যবহার করতে পারে যেখানে থ্রেডগুলি পুল করা হয়।

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

অবশ্যই একবার চিহ্নিত হয়ে গেলে সমস্যাটি সহজেই সমাধান করা যায়।


10

সাক্ষাত্কারকারীর একটি বিজ্ঞপ্তি রেফারেন্স সমাধান খুঁজছেন হতে পারে:

    public static void main(String[] args) {
        while (true) {
            Element first = new Element();
            first.next = new Element();
            first.next.next = first;
        }
    }

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

-আমাদের টারলে


12
রেফারেন্স গণনা আবর্জনা সংগ্রহকারীদের সাথে এটি একটি ক্লাসিক সমস্যা। এমনকি 15 বছর আগে জাভা রেফ গণনা ব্যবহার করেনি। সূত্র। জিসির চেয়ে গণনাও ধীর।
বেটসেস

4
স্মৃতি ফুটো নয়। কেবল একটি অসীম লুপ।
এসবেন স্কোভ পেডারসেন

2
@ এসবেন প্রতিটি পুনরুক্তিতে, পূর্ববর্তীটি কার্যকর firstনয় এবং আবর্জনা সংগ্রহ করা উচিত। ইন রেফারেন্স কাউন্টিং আবর্জনা সংগ্রাহক, বস্তুর freeed হবে না (নিজে) এটা একটি সক্রিয় রেফারেন্সে না থাকায়। অসীম লুপটি এখানে ফুটোটি প্রকাশ করার জন্য: আপনি যখন প্রোগ্রামটি চালাবেন, তখন স্মৃতিটি অনির্দিষ্টকালের জন্য বাড়বে।
rd

@rds @ ওয়েসলি টারলে ধরুন লুপটি অসীম নয় । এখনও কি স্মৃতি ফুটো হতে পারে?
nz_21
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.