2013-10-31 6 views
9

मैं की शैली में कोड का एक टुकड़ा बारे में एक टिप्पणी की थी:बार-बार एक अज्ञात वर्ग को बर्बाद कर रहा है?

Iterable<String> upperCaseNames = Iterables.transform(
    lowerCaseNames, new Function<String, String>() { 
     public String apply(String input) { 
      return input.toUpperCase(); 
     } 
    }); 

व्यक्ति ने कहा कि हर बार जब मैं इस कोड के माध्यम से जाना है, मैं इस अनाम समारोह वर्ग का दृष्टांत, और मैं इसके बजाए एक ही होना चाहिए कि उदाहरण में, एक स्थैतिक चर:

static Function<String, String> toUpperCaseFn = 
    new Function<String, String>() { 
     public String apply(String input) { 
      return input.toUpperCase(); 
     } 
    }; 
... 
Iterable<String> upperCaseNames = 
    Iterables.transform(lowerCaseNames, toUpperCaseFn); 

एक बहुत ही सतही स्तर पर, यह किसी भी तरह से समझ में आता है; एक वर्ग को कई बार तुरंत चालू करना स्मृति या कुछ बर्बाद करना है, है ना?

दूसरी तरफ, लोग कोड के मध्य में गुमनाम कक्षाओं को तत्काल नहीं करते हैं जैसे कल नहीं है, और संकलक के लिए इसे अनुकूलित करने के लिए यह छोटा होगा।

क्या यह एक वैध चिंता है?

+1

जावा में ऑब्जेक्ट आवंटन बेहद तेज़ है। और एक अज्ञात वर्ग को तुरंत चालू करना "नियमित" वर्ग से अलग नहीं है। चूंकि अज्ञात वर्ग में कोई आवृत्ति चर नहीं है, शायद ही कोई स्मृति उपयोग की जाती है (और ऑब्जेक्ट को स्टैक पर आवंटित किया जा सकता है - लेकिन मुझे इसके बारे में निश्चित नहीं है)। लेकिन वह व्यक्ति मूल रूप से सही है: एक लूप में वस्तुओं को तत्काल * * महंगा हो सकता है। लेकिन इसका गुमनाम वर्गों से कोई लेना देना नहीं है, यह किसी भी वर्ग को तत्काल करने के लिए सच है। –

+0

मैं "कई डिस्पोजेबल कक्षाएं बनाने" द्वारा "सीपीयू चक्र" बर्बाद कर देता हूं। फिर फिर, मैं डेस्कटॉप/सर्वर के लिए लिखता हूं और * मुझे कोई परवाह नहीं है कि मैं मिलीसेकंड या दो [समग्र] * बचा सकता हूं। इसके बजाए, कोड लिखें ताकि यह कारण हो सके कि कौन सा * हो सकता है (या हो सकता है) का अर्थ "पुन: उपयोग करना" और/या इसे एक मोनिकर देना है - और उसके बाद इसे प्रोफ़ाइल दें। कोई प्रोफाइल मुद्दा नहीं है? कोई बात नहीं! – user2864740

+0

यह अपमानजनक है अगर यह अपमानजनक है। तथ्य यह है कि यह एक अज्ञात वर्ग है इसके साथ कुछ लेना देना नहीं है। – EJP

उत्तर

7

सूर्य/Oracle JVM अनुकूलन के बारे में मज़ेदार तथ्य, यदि आप एक उद्देश्य यह है कि धागे के बाहर नहीं पहुंचेगी का दृष्टांत, JVM पैदा करेगा ढेर के बजाय ढेर पर वस्तु।

आमतौर पर, स्टैक आवंटन उन भाषाओं से जुड़ा होता है जो स्मृति मॉडल का खुलासा करते हैं, जैसे सी ++। आपको C++ में delete स्टैक वेरिएबल्स नहीं हैं क्योंकि जब दायरा बाहर निकलता है तो वे स्वचालित रूप से हटा दिए जाते हैं। यह आवंटन ढेर के विपरीत है, जिसके लिए आपको पॉइंटर को हटाने की आवश्यकता होती है जब आप इसके साथ काम करते हैं।

सूर्य/ओरेकल जेवीएम में, बाइटकोड का विश्लेषण यह तय करने के लिए किया जाता है कि कोई ऑब्जेक्ट थ्रेड से बच सकता है या नहीं। वहाँ three levels of escape हैं:

  1. नहीं बच - वस्तु केवल विधि/गुंजाइश यह बनाई गई है भीतर प्रयोग किया जाता है, और वस्तु धागा बाहर पहुँचा नहीं जा सकता।
  2. स्थानीय/Arg escape - ऑब्जेक्ट उस विधि द्वारा वापस लौटाया जाता है जो इसे बनाता है या जिस विधि को कॉल करता है उसे पास कर दिया जाता है, लेकिन वर्तमान स्टैक ट्रेस में से कोई भी तरीका उस ऑब्जेक्ट को कहीं भी नहीं रखेगा जिसे इसे बाहर से पहुंचा जा सकता है धागा।
  3. वैश्विक भागने - ऑब्जेक्ट कहीं और रखा जाता है जिसे इसे किसी अन्य थ्रेड में एक्सेस किया जा सकता है।

यह मूल रूप से प्रश्नों के समान है, 1) क्या मैं इसे पास/वापस कर देता हूं, और 2) क्या मैं इसे जीसी रूट से जुड़ा हुआ कुछ जोड़ता हूं? आपके विशेष मामले में, अज्ञात ऑब्जेक्ट को " no स्थानीय भागने" के रूप में टैग किया जाएगा और इसे स्टैक पर आवंटित किया जाएगा, फिर for लूप के प्रत्येक पुनरावृत्ति पर केवल स्टैक को पॉप करके साफ़ किया जाएगा, इसलिए इसे साफ़ करना होगा अत्यधिक तीव्र। क्षमा करें, जब मैंने अपना जवाब लिखा था तो मैं ज्यादा ध्यान नहीं दे रहा था। यह वास्तव में स्थानीय भाग है, जिसका मतलब है कि किसी भी ताले (पढ़ें: synchronized का उपयोग) ऑब्जेक्ट पर अनुकूलित किया जाएगा। (किसी ऐसे थ्रेड पर सिंक्रनाइज़ क्यों करें जो किसी अन्य थ्रेड में कभी भी उपयोग नहीं किया जाएगा?) यह "नो एस्केप" से अलग है, जो स्टैक पर आवंटन करेगा। यह ध्यान रखना महत्वपूर्ण है कि यह "आवंटन" ढेर आवंटन के समान नहीं है। यह वास्तव में क्या करता है गैर-भागने वाली वस्तु के अंदर सभी चर के लिए ढेर पर स्थान आवंटित करता है। यदि आपके पास 3 फ़ील्ड, int, String, और MyObject नो-एस्केप ऑब्जेक्ट के अंदर हैं, तो तीन स्टैक वैरिएबल आवंटित किए जाएंगे: int, String संदर्भ, और MyObject संदर्भ। ऑब्जेक्ट आवंटन को तब अनुकूलित किया जाता है और कन्स्ट्रक्टर/विधियों को ढेर चर के बजाय स्थानीय स्टैक चर का उपयोग करके चलाया जाएगा।

कहा जा रहा है, यह मेरे लिए समयपूर्व अनुकूलन की तरह लगता है। जब तक कोड बाद में धीमा साबित न हो और प्रदर्शन समस्याओं का कारण बनता है, तो आपको इसकी पठनीयता को कम करने के लिए कुछ भी नहीं करना चाहिए। मेरे लिए, यह कोड बहुत पठनीय है, मैं इसे अकेला छोड़ दूंगा। यह निश्चित रूप से पूरी तरह से व्यक्तिपरक है, लेकिन "प्रदर्शन" कोड बदलने का एक अच्छा कारण नहीं है जब तक कि इसके एल्गोरिदमिक चलने वाले समय के साथ कुछ नहीं किया जाता है। आमतौर पर, समयपूर्व अनुकूलन एक मध्यवर्ती स्तर के कोडर का संकेतक होता है। "विशेषज्ञ" (यदि ऐसी कोई चीज है) तो केवल कोड लिखें जो बनाए रखना आसान है।

+0

एचएम। आपके द्वारा बचने के स्तर के बारे में पोस्ट किए गए लिंक में यह टेक्स्ट है: "बचने के विश्लेषण के बाद, सर्वर कंपाइलर ** स्केलर प्रतिस्थापन योग्य ऑब्जेक्ट आवंटन ** और जेनरेट कोड से जुड़े ताले को हटा देता है। सर्वर कंपाइलर सभी गैर-वैश्विक रूप से भागने वाली वस्तुओं के लिए ताले को भी हटा देता है।यह ** गैर-वैश्विक रूप से बचने वाली वस्तुओं के लिए एक ढेर आवंटन ** के साथ एक ढेर आवंटन को प्रतिस्थापित नहीं करता है। " – user711413

+0

@ user711413 इसे जल्दी से एक साथ रखो और स्पष्ट रूप से नहीं सोच रहा था, क्षमा करें। मैं अपना जवाब अपडेट करूंगा। – Brian

+1

असल में , उस फ़ंक्शन को प्राप्त करने वाले कोड को रेखांकित करने के बाद, फ़ंक्शन ऑब्जेक्ट "नो एस्केप" स्थिति में बदल सकता है (उस विधि के आधार पर)। लेकिन इसका मतलब यह नहीं है कि एक स्टैक आवंटन होगा-क्योंकि ऑब्जेक्ट कोई राज्य नहीं है , कोई आवंटन नहीं होगा। इसके बजाय, फ़ंक्शन का तर्क आवेदित विधि (इस संदर्भ में) के कोड में रेखांकित होगा। फिर भी, जब इसे लैम्ब्डा अभिव्यक्ति के साथ बदल दिया जाता है, तो आपको एक सिंगलटन मिल जाएगा, भले ही ऑब्जेक्ट से बच निकलता है। इसलिए जावा 8 हमें ऐसी चीजों के बारे में सोचने की आवश्यकता से मुक्त करता है। – Holger

1

संक्षिप्त उत्तर: नहीं - चिंता न करें।

लंबा उत्तर: यह निर्भर करता है कि आप इसे कितनी बार तत्काल कर रहे हैं। यदि अक्सर क्विक लूप लूप में, हो सकता है - हालांकि ध्यान दें कि जब फ़ंक्शन लागू किया जाता है तो यह String.toUpperCase() को Iterable में प्रत्येक आइटम के लिए कॉल करता है - प्रत्येक कॉल संभवतः एक नया String बनाता है, जो अधिक जीसी मंथन बनाएगा।

"समय से पहले अनुकूलन सब बुराई की जड़ है" - नुथ

1

इस सूत्र मिला: Java anonymous class efficiency implications, आप पा सकते यह दिलचस्प

कुछ सूक्ष्म बेंच मार्किंग किया। माइक्रो-बेंचमार्क के बीच एक तुलना थी: एक लूप पुनरावृत्ति प्रति (स्थिर आंतरिक) वर्ग को तत्काल, एक (स्थैतिक आंतरिक) कक्षा को एक बार चालू करना और लूप में इसका उपयोग करना, और दो समान लेकिन अज्ञात वर्गों के साथ। माइक्रो बेंचमार्किंग के लिए कंपाइलर गुमनाम वर्ग को लूप से बाहर निकालने लग रहा था और भविष्यवाणी के रूप में, अज्ञात वर्ग को कॉलर के एक आंतरिक वर्ग में प्रचारित किया गया था। इसका मतलब है कि सभी चार विधियां गति में अलग-अलग थीं। मैंने इसे एक बाहरी कक्षा और फिर, एक ही गति से तुलना की। अज्ञात वर्गों वाले व्यक्ति ने शायद

http://jdmaguire.ca/Code/Comparing.java & http://jdmaguire.ca/Code/OutsideComp.java पर मेरा माइक्रो-बेंचमार्क देख सकते हैं। मैंने इसे WordLen, sortTimes, और listLen के लिए विभिन्न मानों पर चलाया। साथ ही, JVM गर्म होने में धीमा है इसलिए मैंने विधि कॉल को चारों ओर घुमाया। कृपया भयानक गैर-टिप्पणी कोड के लिए मेरा न्याय न करें। मैं आरएल में उससे बेहतर कार्यक्रम। और माइक्रोबेंचिंग अंकन समयपूर्व अनुकूलन के रूप में लगभग बुरा और बेकार है।

संबंधित मुद्दे