2012-10-15 6 views
8

मैं कार्यों को चलाने के लिए ThreadPoolExecutor का उपयोग कर रहा हूं। बैकएंड SynchronousQueue है, इसलिए यदि निष्पादक पहले से ही कार्य कर रहा है, तो यह RejectedExecutionException फेंकता है। यहाँ एक सरल परीक्षण का मामला है:क्या मेरा ThreadPoolExecutor स्मृति लीक कर रहा है?

public class ExecutorTest { 

    final static Worker worker = new Worker(); 

    public static void main(String[] args) { 
    ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new SynchronousQueue<Runnable>()); 

    while (true) { 
     try {     
      executor.execute(worker);     
     }catch (RejectedExecutionException e) {     
     } 
    }   
    } 

    static class Worker implements Runnable { 

    private int i = 0; 
    private long start = System.currentTimeMillis(); 

    @Override 
    public void run() { 
     try { 
      Thread.sleep(1000); 
      System.out.println(++i + " " + (System.currentTimeMillis() - start)); 
     } catch (InterruptedException ex) {     
     } 
    } 
    } 
} 

उम्मीद bahavious है: कार्यकर्ता निष्पादित और एक पल के लिए सो के बाद, प्रिंट आउट मैं (का प्रतिनिधित्व कितनी बार कार्यकर्ता अब तक फांसी दे दी जाती है) और के बाद से मिलीसेकेंड की राशि कार्यकर्ता बनाया गया था। इसलिए मैं उम्मीद कर रहा हूँ:

1 1015 
2 2015 
3 3016 
4 4017 

यह थोड़ी देर के लिए ठीक काम करता है, लेकिन लगभग घंटे पर बाद:

2919 2922196 
2920 2942951 
2921 2990407 

तो एक कार्यकर्ता निष्पादन और अगले एक के बीच समय की राशि 20 सेकंड है (2 9 1 9-> 2 9 20) और 38 सेकंड (2 9 20-> 2 9 21) और बहुत आगे। सब कुछ बेहद धीमा हो जाता है और जेवीएम कचरा संग्रह में बहुत समय बिताता है। अंत में (कुछ दिनों के बाद) मैं एक आउटऑफमेमरी एरर में चला जाता हूं।

मैं इसे 64x लिनक्स मशीन पर ओरेकल के जेवीएम 1.7.0_07 पर -Xmx8M (मुझे लगता है कि प्रभाव अधिक हीप स्पेस के साथ बाद में दिखाई देता है) के साथ चल रहा है। मैं किसी भी पॉइंटर्स की सराहना करता हूं, लेकिन शायद मैं सिर्फ स्पष्ट याद कर रहा हूं।

+1

हो सकता है कि ढेर कुछ समय बाद अस्वीकृत एक्सेक्यूशन एक्सेप्शन के साथ भीड़ हो रहा हो (हालांकि मुझे लगता है कि थोड़ी देर बाद अपवाद ऑब्जेक्ट्स का पुन: उपयोग किया गया था)? क्या आपने अपना ऐप प्रोफाइल करने का प्रयास किया है? – assylias

+0

@ वासिलियास वेल, मैंने निश्चित रूप से ऐप का प्रोफाइल किया, लेकिन मूर्खतापूर्वक केवल हीप स्पेस और जीसी जीवित पीढ़ियों को देखा। मैं अभी जांच करने के लिए प्रोफाइलर चला रहा हूं, लेकिन पहली नज़र में RejctedExectutionExceptions अपराधी प्रतीत नहीं होता है। यहां तक ​​कि अगर वे हैं, तो मुझे उन अपवादों को पकड़ना होगा और दिन के अंत में स्मृति से बाहर नहीं होना चाहिए, है ना? –

+0

जो जीसी की बढ़ी हुई राशि को समझाएगा लेकिन ओओएमई नहीं ... – assylias

उत्तर

2

आप ThreadPoolExecutor तत्कालता को संशोधित करने का प्रयास कर सकते हैं। आपको RejectExecutionHandler का उपयोग करने के लिए केवल कन्स्ट्रक्टर में एक तर्क जोड़ना होगा जो चुपचाप अस्वीकृत कार्यों को त्याग देगा।

public static void main(String[] args) { 
    ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new SynchronousQueue<Runnable>(), new ThreadPoolExecutor.DiscardPolicy()); 

    while (true) { 
    executor.execute(worker);     
    } 
} 

तो यदि आपकी समस्या (और मुझे ऐसा लगता है) दोहराया RejectedExecutionException से आता है, तो आप इसे से बचने जाएगा।

+1

+1 यह '-verbose: gc -XX: + PrintGCDetails' द्वारा दिखाए गए अनुसार जीसी गतिविधि की मात्रा को बहुत कम करता है। – DNA