2012-05-24 10 views
8

हमारे पास एक जावा/जर्बी वेबपैम टॉमकैट के तहत चल रहा है, और मैं रनटाइम के दौरान ऐप द्वारा ऑब्जेक्ट्स और मेमोरी उपयोग की संख्या का विश्लेषण कर रहा हूं। स्टार्टअप के बाद मैंने देखा है कि कक्षा "org.jruby.RubyString" स्ट्रिंग के 1,118,000 उदाहरण थे, "अकेले खाली तारों द्वारा उपयोग की जाने वाली हीप मेमोरी की कुल मात्रा 65 एमबी है, यह मेरे लिए हास्यास्पद है क्योंकि यह स्मृति का 15% है वेबपैप द्वारा प्रयोग किया जाता है। रिक्त स्ट्रिंग इस समस्या के साथ कई स्ट्रिंग मानों का केवल एक उदाहरण है, यदि मैं उन सभी जर्बी स्ट्रिंग्स को प्रशिक्षित कर सकता हूं जो मैंने काम किया है तो मैं लगभग 130 एमबी बचा सकता हूं।क्या जर्बी रनटाइम इंटर्न सभी तारों को बनाने का कोई तरीका है?

मैं जावा में जानता हूं, हर बार जब एक स्ट्रिंग मान बनाया जाता है, तो यह जांच करेगा कि क्या स्ट्रिंग पूल में मान पहले से मौजूद है और यदि यह करता है तो इसका पुन: उपयोग करें। मुझे आश्चर्य है कि क्या जुरुबी में कोई विकल्प है जिसमें वही अनुकूलन है? यदि हां, तो मैं इसे कैसे सक्षम करूं? JRuby में

उदाहरण: जावा में

v1 = "a" 
v2 = "a" 
puts v1.object_id # => 3352 
puts v2.object_id # => 3354 

उदाहरण:

String v1 = "a"; 
String v2 = "a"; 

System.out.println(v1.hashCode()); # => 97 
System.out.println(v2.hashCode()); # => 97 
+0

यदि आप सभी स्ट्रिंग्स को सिंबल के साथ प्रतिस्थापित करते हैं तो आपको वह व्यवहार मिल जाएगा, लेकिन मुझे इसे स्ट्रिंग स्वचालित रूप से इंटर्न करने के विकल्प के बारे में पता नहीं है। –

+0

कोई आदर्श समाधान नहीं है क्योंकि इन तारों में से बहुत से तृतीय पक्ष रत्न और प्लगइन से बनाए जाते हैं। –

+0

क्या आप कोड के उन टुकड़ों में से एक प्रकाशित कर सकते हैं जो इन खाली तारों का उत्पादन करते हैं? – peter

उत्तर

2
v1 = v2 = v3 = "a" 

केवल रूबी, नहीं तीन में से एक वस्तु का निर्माण करेगा।

v1 = v2 = v3 = "a" # => "a" 
v1.object_id # => 10530560 
v2.object_id # => 10530560 
v1 << "ll the same" # => "all the same" 
v2 # "all the same" 

सभी स्ट्रिंग्स होना शामिल के रूप में के रूप में कठोर कुछ करने से पहले, मैं अन्य बिल्ला उपयोगकर्ताओं के साथ जांच चाहते हैं, तो इस इस समस्या से निपटने का सबसे अच्छा तरीका है। मैं टोमकैट या जेआरबी का उपयोग नहीं करता, लेकिन मुझे दृढ़ता से संदेह है कि यह सबसे अच्छा तरीका नहीं है।

संपादित करें यदि "ऑब्जेक्ट" से बनाया गया प्रत्येक ऑब्जेक्ट एक ही ऑब्जेक्ट था, तो उनमें से एक को संशोधित करने से अन्य सभी तारों को संशोधित किया जाएगा। यह दुष्प्रभाव दुःस्वप्न होगा।

+0

मेरी टिप्पणी में मेरा उदाहरण पहले एक आलसी उदाहरण था। कोशिश करें, एक = "ए", बी = "ए" और 2 ऑब्जेक्ट्स में अलग ऑब्जेक्ट_आईड होगा। –

1

एक ही रास्ता प्रशिक्षु के लिए JRuby में एक स्ट्रिंग कॉल करने के लिए to_sym या intern (वे एक दूसरे उपनाम), और इस तरह उन्हें प्रतीकों बना रही है - जो, जैसा कि आप उल्लेख किया है, तीसरे पक्ष के रत्नों के लिए काफी मदद नहीं करता है। जहां तक ​​मुझे पता है, कोई अन्य तरीका नहीं है।

इस एमआरआई व्यवहार के अनुरूप है:

[email protected]:~$ rvm ruby-1.9.3-p0 
[email protected]:~$ irb 
1.9.3p0 :001 > a = "Hello World" 
=> "Hello World" 
1.9.3p0 :002 > b = "Hello World" 
=> "Hello World" 
1.9.3p0 :003 > a.object_id 
=> 20126420 
1.9.3p0 :004 > b.object_id 
=> 19289920 
+0

यहां तक ​​कि '# to_sym' को कॉल करने से भी मदद नहीं मिलती है क्योंकि उस बिंदु पर स्ट्रिंग ऑब्जेक्ट पहले से ही बनाया जा चुका है। इसे शुरू करने के लिए एक प्रतीक होना चाहिए। 'स्ट्रिंगबिल्डर' वाक्य के लिए – Theo

5

मैं इसके पीछे प्रेरणा समझते हैं, लेकिन वहाँ वास्तव में JRuby में ऐसी कोई "जादू" स्विच है ...

एक जावा पृष्ठभूमि यह महसूस करता है से तारों पर सहेजने के लिए temping, लेकिन आप JRuby में तारों के समान व्यवहार करने की उम्मीद नहीं कर सकते हैं जैसा कि वे जावा में करते हैं। सबसे पहले वे एक पूरी तरह से अलग वस्तु हैं। मैं कहूंगा कि रूबी String जावा StringBuilder से अधिक है।

यह निश्चित रूप से एक कचरा है कि "" उदाहरण झूठ बोल रहे हैं, लेकिन यदि आप जिस कोड का उल्लेख करते हैं वह तीसरे पक्ष के कोड है तो आप इसके बारे में इतना कुछ नहीं कर सकते हैं - जब तक कि आप बंदर को बहुत पैचिंग महसूस न करें। मैं उन स्थानों की पहचान करने की कोशिश करता हूं जिनमें से अधिकांश उदाहरण आते हैं और उन्हें दोबारा दोहराते हैं - लेकिन याद रखें कि तारों को बचाने पर कुछ "मुश्किल" भाग हैं। Hash साथ:

{ 'foo' => 'bar' } 

आप इस 3 वस्तुओं बनाता है लगता है, लेकिन आप गलत होगा; यह वास्तव में 'foo' में से दो बनाता है।चूंकि String म्यूटेबल है (जब तक frozen?) dup एस स्ट्रिंग और freeze एस Hash कुंजी के रूप में उपयोग किए जाने पर (और उसके लिए एक अच्छा कारण है)।

"समझदारी से" प्रतिक्रिया देने के लिए भी ध्यान रखें - यदि आप आवंटित उदाहरणों पर सस्ते होने की कोशिश करके चीजों को धीमा नहीं करते हैं तो आप जिस बिट्स को बदल रहे हैं उसे प्रोफ़ाइल करें।

+0

+1। –

+0

जानकारीपूर्ण उत्तर, लेकिन मूल रूप से "जर्बी (और संभवतः रूबी) स्ट्रिंग अक्षम हैं, इसलिए इसके साथ रहें।" हालांकि यह अंतिम शब्द हो सकता है, यह आरामदायक नहीं है। – Glenn

+0

@Glenn क्षमा करें, लेकिन चूंकि वहां तीसरे पक्ष के कोड शामिल हैं, इसलिए मुझे लगता है कि वास्तव में कोई बेहतर जवाब नहीं है। कुछ रत्न पहले से ही इसे स्वीकार करते हैं और स्थिरता में तारों को संग्रहित करते हैं और उन्हें स्थिरांक में संग्रहीत करते हैं। https://github.com/puma/puma/blob/master/lib/puma/const.rb, जबकि अन्य, दुर्भाग्य से, मान लें कि वे 'स्ट्रिंग' विधि पैरामीटर को संशोधित कर सकते हैं। कुछ बिंदु पर jruby (लेकिन यहां तक ​​कि एमआरआई) कुछ 'स्ट्रिंग' "स्थिरांक का पुन: उपयोग करने की कोशिश करने का एक ह्युरिस्टिक कर सकता है लेकिन मुझे संदेह है कि वे बहुत कुछ कर सकते हैं, यह ज्यादातर प्रोग्रामर पर छोड़ दिया गया है ... – kares

0

यह अब जेआरबी में डिफ़ॉल्ट व्यवहार है। संस्करण 9.1 से सभी जमे हुए स्ट्रिंग अक्षर (उदा। 'hello'.freeze) एक ही उदाहरण लौटाते हैं, और यह हैश कुंजी के रूप में उपयोग किए जाने वाले शाब्दिक तारों के लिए जाता है (उदा। stuff['thing']) और कुछ अन्य मामले। JRuby issue #3491 देखें।

यदि आप आक्रामक रूप से सभी स्ट्रिंग अक्षरों को फ्रीज करना चाहते हैं तो आप --enable-frozen-string-literal के साथ जेआरबी (9.1+) और रुबी (2.3+) दोनों चला सकते हैं, लेकिन चीजों को तोड़ने के लिए तैयार करें क्योंकि अधिकांश रत्न मानते हैं कि स्ट्रिंग्स म्यूटेबल हैं।

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