2015-08-25 3 views
5

मैं एक असामान्य आवश्यकता है: मेरा आवेदन एक बहुत लंबे स्क्रिप्ट (एक गतिशील रूप से टाइप भाषा में लिखे गए) से स्वचालित रूप से जावा कोड उत्पन्न करता है। लिपि इतनी लंबी है कि मैंने the maximum method size of 65k of the JVM मारा।जावा - कैसे अपने आप जेनरेट कोड में अधिकतम विधि आकार काबू पाने के लिए

लिपि में केवल प्राचीन प्रकारों पर सरल निर्देश शामिल हैं (गणितीय के अलावा अन्य कार्यों के लिए कोई कॉल नहीं)। सभी

  • बारी: यह की तरह लग रहे हो सकता है:

    ... 
    a = b * c + sin(d) 
    ... 
    if a>10 then 
        e = a * 2 
    else 
        e = a * abs(b) 
    end 
    ... 
    

    ... जो तब्दील हो जाता है के रूप में:

    ... 
    double a = b * c + Math.sin(d); 
    ... 
    double e; 
    if(a>10){ 
        e = a * 2; 
    }else{ 
        e = a * Math.abs(b); 
    } 
    ... 
    


    मेरा पहला विचार विधि आकार सीमा को पार करने के लिए पीछा कर रहा था खेतों में स्थानीय चर
  • स्प्लिट कोड हर 100 लाइनों (या उससे अधिक समय अगर एक अगर/बाकी ब्लॉक के मामले में आवश्यक) सितम्बर में arate विधियों।

कुछ की तरह:

class AutoGenerated { 

    double a,b,c,d,e,....; 

    void run1(){ 
     ... 
     a = b * c + sin(d); 
     ... 
     run2(); 
    } 

    void run2(){ 
     ... 
     if(a>10){ 
      e = a * 2; 
     }else{ 
      e = a * Math.abs(b); 
     } 
     ... 
     run3(); 
    } 

    ... 
} 

आप किसी अन्य तरीके कि और अधिक कुशल हो जाएगा का पता है? ध्यान दें कि मुझे जितनी जल्दी हो सके चलाने के लिए कोड की आवश्यकता है क्योंकि इसे लंबे लूप में निष्पादित किया जाएगा। मैं, सी के संकलन का सहारा नहीं कर सकते हैं के रूप में अंतर भी एक मुद्दा है ...

मैं भी पुस्तकालयों है कि मुझे मदद कर सकता है की ओर इशारा की सराहना करेंगे।

+0

आप दक्षता के बारे में चिंतित हैं, तो आप को ध्यान देना चाहिए कि आकार में तरीकों से 8 KB डिफ़ॉल्ट रूप से संकलित नहीं कर रहे हैं। –

+0

मैं विचार करता हूं कि आपके लिए इनलाइनिंग क्या कर सकती है। क्या कोड का कोई दोहराना अनुक्रम है जो इनलाइनिंग के बाद एक ही कोड उत्पन्न करेगा? –

+0

@ पीटर लेवरी, 8KB से अधिक क्या होता है? क्या कोड का अर्थ है, बहुत सारी दक्षता की लागत है? संकलक यह तय करता है कि इसे संकलित करना चाहिए या नहीं? * इनलाइनिंग * के बारे में, यह वास्तव में कैसे काम करेगा? क्या मुझे कोड में "पैटर्न" की तलाश करनी चाहिए और उन्हें संभालने के लिए समर्पित तरीके बनाना चाहिए? –

उत्तर

2

हम अपने नुकसान के अन्य लोगों द्वारा उल्लेख के बावजूद परियोजनाओं में से एक में इसी तरह के दृष्टिकोण का उपयोग कर रहे हैं। हम एकाधिक लॉन्चर विधि से कई जेनरेट किए गए तरीकों को कॉल करते हैं जैसे @ मार्को 13 सुझाव देता है। हम वास्तव में उत्पन्न बाइटकोड के आकार (काफी सटीक) की गणना करते हैं और सीमा तक पहुंचने पर ही एक नई विधि शुरू करते हैं। हमारे गणित सूत्र जिन्हें हम जावा कोड में अनुवाद करते हैं, एस्टट्री के रूप में उपलब्ध हैं और हमारे पास एक विशेष विज़िटर है जो प्रत्येक अभिव्यक्ति के लिए बाइटकोड लंबाई की गणना करता है। ऐसे सरल कार्यक्रमों के लिए यह जावा संस्करणों और विभिन्न कंपाइलरों में काफी स्थिर है। इसलिए हम आवश्यकतानुसार विधियों को अधिक नहीं बनाते हैं। हमारे मामले में सीधे बाइटकोड उत्सर्जित करना काफी मुश्किल है, लेकिन आप एएसएम या इसी तरह की लाइब्रेरी का उपयोग करके अपनी भाषा के लिए ऐसा करने का प्रयास कर सकते हैं (इस तरह, निश्चित रूप से, एएसएम आपके लिए बाइटकोड लंबाई की गणना करेगा)।

हम आम तौर पर एक double[] सरणी में डेटा चर की दुकान (हम अन्य प्रकार की जरूरत नहीं है) और पैरामीटर के रूप में इसे पारित। इस तरह आपको बड़ी संख्या में फ़ील्ड की आवश्यकता नहीं है (कभी-कभी हमारे पास हजारों चर होते हैं)। दूसरी ओर स्थानीय सरणी का उपयोग पर की तुलना में 127

एक और चिंता का विषय निरंतर पूल आकार है उच्च सूचकांक के लिए क्षेत्र का उपयोग की तुलना में अधिक बाईटकोड बाइट्स लग सकता है। हमारे पास आमतौर पर स्वत: जेनरेटेड कोड में कई डबल स्थिरांक होते हैं। यदि आप कई फ़ील्ड और/या विधियों की घोषणा करते हैं, तो उनके नाम निरंतर पूल प्रविष्टियां भी लेते हैं। इसलिए वर्ग निरंतर पूल सीमा को हिट करना संभव है। कभी-कभी हम इसे प्रभावित करते हैं और इस समस्या को दूर करने के लिए नेस्टेड कक्षाएं उत्पन्न करते हैं।

अन्य लोगों को JVM विकल्पों बदलाव करने के साथ-साथ सुझाव देते हैं। इन सलाहयों का सावधानी से उपयोग करें क्योंकि वे न केवल इस स्वत: उत्पन्न वर्ग को प्रभावित करेंगे, बल्कि हर दूसरे वर्ग को भी प्रभावित करेंगे (मुझे लगता है कि अन्य कोड आपके मामले में उसी JVM में भी निष्पादित किया गया है)।

0

मैं एक दुभाषिया या शायद एक इन-लाइन संकलक लिखने के लिए परीक्षा की जाएगी। आपको कुछ गति लाभ भी मिल सकते हैं क्योंकि परिणामस्वरूप अधिकतर छोटे कोड बेस अधिक आसानी से कैश करेंगे।

+0

क्या आप मूल भाषा की व्याख्या करने वाले जावा में एक दुभाषिया (जावा में) को कोड करना चाहते हैं? एक ऑनलाइन कंपाइलर कैसे काम करता है और आप कैसे लिखते हैं? –

+0

@EricLeibenguth - एक इन-लाइन कंपाइलर भाषा पढ़ेगा और डेटा स्ट्रक्चर का निर्माण करेगा जिसे बाद में निष्पादित किया जा सकता है - शायद एक राज्य मशीन की तरह कुछ। यह एक इंटरप्टर से तेज हो सकता है। – OldCurmudgeon

+0

ठीक है, मैं देखता हूं कि आपका क्या मतलब है, लेकिन यह खुद को बनाने के लिए थोड़ा जटिल लगता है। शायद आप एक पुस्तकालय के बारे में जानते हैं जो मदद कर सकता है? –

0
    क्षेत्रों

कि थोड़ी सी भी प्रभाव नहीं होगा में

  • बारी सभी स्थानीय चर। विधि का आकार == कोड आकार। स्थानीय चर के साथ कुछ भी नहीं करना, जो केवल आमंत्रण फ्रेम आकार को प्रभावित करता है।

    • स्प्लिट कोड हर 100 लाइनों (या उससे अधिक समय अगर एक अगर/बाकी ब्लॉक के मामले में आवश्यक) अलग तरीकों में।

    यह आपकी पूरी पसंद है, एक पूरी तरह से अलग कार्यान्वयन रणनीति के अलावा।

    कोड जनरेटर के साथ समस्या यह है कि वे कोड उत्पन्न करते हैं।

  • +1

    फ़ील्ड में स्थानीय चर बदलना विधि को विभाजित करने के लिए एक एनाबेलर था (मुझे यह समझने की ज़रूरत नहीं है कि विधि 1 को किस विधि को पास करना चाहिए, क्योंकि सभी चर फ़ील्ड के रूप में उपलब्ध हैं) –

    1

    क्षेत्रों में स्थानीय चर परिवर्तित वास्तव में प्रदर्शन पर नकारात्मक प्रभाव जब तक कोड JIT से अनुकूल नहीं है (आगे infos के लिए this question and related ones देखें) हो सकता है। लेकिन मैं देखता हूं कि इसमें शामिल चर के आधार पर, शायद ही कभी अन्य व्यवहार्य विकल्प हो सकते हैं।


    संकलन और विधि आकार के लिए अतिरिक्त सीमा नहीं हो सकता है। पीटर लॉरी ने टिप्पणियों में उल्लेख किया कि "... आकार में 8 KB से अधिक विधियों को डिफ़ॉल्ट रूप से संकलित नहीं किया गया है" - मुझे इस बारे में पता नहीं था, लेकिन वह आमतौर पर जानता है कि वह किस बारे में बात कर रहा है, इसलिए आपको थोड़ा खोदना चाहिए यहाँ गहरा इसके अतिरिक्त, आप यह देखने के लिए HotSpot VM options पर एक नज़र डालना चाहते हैं कि कौन सी सीमाएं और सेटिंग्स आपके लिए प्रासंगिक हो सकती हैं। मैंने मुख्य रूप से सोचा कि

    -XX:MaxInlineSize=35: एक विधि का अधिकतम बाइटकोड आकार रेखांकित किया जाना चाहिए।

    कुछ भी ध्यान में रखना हो सकता है।

    (वास्तव में, MaxInlineSize कि इनलाइन किए जाने वाले इन सभी कॉल्स से अधिक होगा की एक आकार के साथ तो कई तरीके बुला युक्त विधि के लिए 65k बाइट्स के आकार मजबूती के लिए एक बड़े करीने से-बुरा परीक्षण का मामला हो सकता है और

    void run1(){ 
        ... 
        run2(); 
    } 
    
    void run2(){ 
        ... 
        run3(); 
    } 
    
    : इनलाइनिंग प्रक्रिया के किनारे मामले परीक्षण ...)


    आप तरीकों के लिए एक "telescoping" कॉल योजना तय की

    इससे समस्याएं भी हो सकती हैं: यह ध्यान में रखते हुए कि आपके पास इन तरीकों में से 650 (सर्वोत्तम मामले में) हैं, यह कम से कम बहुत गहरे ढेर का कारण बन जाएगा, और वास्तव में StackOverflowError - फिर से निर्भर हो सकता है Memory Options में से कुछ पर। आपको तदनुसार -Xss पैरामीटर सेट करके स्टैक आकार को बढ़ाना पड़ सकता है।


    वास्तविक समस्या वर्णन थोड़ा अस्पष्ट था, और कोड है कि उत्पन्न करने के बारे में अधिक जानकारी के बिना (भी जैसे के बारे में सवाल के बारे में कितने स्थानीय चर की जरूरत है, कि में तब्दील किया जा करना पड़ सकता है उदाहरण चर आदि), मेरा प्रस्ताव चाहते हैं निम्नलिखित:

    • कई छोटे तरीकों बनाएं यदि संभव हो तो (MaxInlineSize)
    • पर विचार पुन: उपयोग इन छोटे तरीकों की कोशिश करें (यदि इस तरह के पुनर्प्रयोग उचित प्रयास के साथ इनपुट)
    • कॉल से इन तरीकों क्रमिक रूप से, के रूप में

      void run() 
      { 
          run0(); 
          run1(); 
          ... 
          run2000(); 
      } 
      

      में ढेर आकार के साथ समस्याओं से बचने के पता लगाया जा सकता।


    हालांकि, अगर आप आगे उदाहरण या विवरण कहा, एक शायद अधिक ध्यान केंद्रित को सलाह दे सके। यह एक "पूर्ण" उदाहरण भी हो सकता है - जरूरी नहीं कि कोडों की हजारों पंक्तियां शामिल हों, लेकिन वास्तविक पैटर्न दिखाएं जो वहां दिखाई देते हैं।

    +0

    उत्तर के लिए धन्यवाद, निश्चित रूप से मदद करता है! कोड का "प्रतिनिधि नमूना" प्रदान करना मुश्किल है, क्योंकि यह संभावित रूप से काफी विविध है। निर्देश स्तर पर कुछ * पुनरावर्ती पैटर्न हैं (एक जैसे दिखने वाली विभिन्न रेखाएं), लेकिन कार्यक्रम स्तर पर बहुत अधिक नहीं (समान रूप से दिखने वाली रेखाओं के ब्लॉक)। –

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