java - एक JVM के गैर-ढेर स्मृति उपयोग की निगरानी करें




performance memory (2)

हम आमतौर पर ढेर या permgen आकार विन्यास समस्या के कारण OutOfMemory त्रुटि समस्याओं से निपटते हैं।

लेकिन सभी जेवीएम मेमोरी परमिट या ढेर नहीं है। जहां तक ​​मैं समझता हूं, यह थ्रेड / स्टैक्स, देशी जेवीएम कोड से भी संबंधित हो सकता है ...

लेकिन pmap का उपयोग करके मैं देख सकता हूं कि प्रक्रिया 9.3 जी के साथ आवंटित की गई है जो 3.3 जी ऑफ-हीप मेमोरी उपयोग है।

मुझे आश्चर्य है कि इस अतिरिक्त ऑफ-हेप मेमोरी खपत की निगरानी और ट्यून करने की संभावनाएं क्या हैं।

मैं सीधे ऑफ-हेप मेमोरी एक्सेस का उपयोग नहीं करता (MaxDirectMemorySize 64m डिफ़ॉल्ट है)

Context: Load testing
Application: Solr/Lucene server
OS: Ubuntu
Thread count: 700
Virtualization: vSphere (run by us, no external hosting)

JVM

java version "1.7.0_09"
Java(TM) SE Runtime Environment (build 1.7.0_09-b05)
Java HotSpot(TM) 64-Bit Server VM (build 23.5-b02, mixed mode)

ट्यूनिंग

-Xms=6g
-Xms=6g
-XX:MaxPermSize=128m

-XX:-UseGCOverheadLimit
-XX:+UseConcMarkSweepGC
-XX:+UseParNewGC
-XX:+CMSClassUnloadingEnabled

-XX:+OptimizeStringConcat
-XX:+UseCompressedStrings 
-XX:+UseStringCache 

मेमोरी मानचित्र:

https://gist.github.com/slorber/5629214

vmstat

procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa
 1  0   1743    381      4   1150    1    1    60    92    2    0  1  0 99  0

मुक्त

             total       used       free     shared    buffers     cached
Mem:          7986       7605        381          0          4       1150
-/+ buffers/cache:       6449       1536
Swap:         4091       1743       2348

चोटी

top - 11:15:49 up 42 days,  1:34,  2 users,  load average: 1.44, 2.11, 2.46
Tasks: 104 total,   1 running, 103 sleeping,   0 stopped,   0 zombie
Cpu(s):  0.5%us,  0.2%sy,  0.0%ni, 98.9%id,  0.4%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:   8178412k total,  7773356k used,   405056k free,     4200k buffers
Swap:  4190204k total,  1796368k used,  2393836k free,  1179380k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND                                                                                                                                 
17833 jmxtrans  20   0 2458m 145m 2488 S    1  1.8 206:56.06 java                                                                                                                                    
 1237 logstash  20   0 2503m 142m 2468 S    1  1.8 354:23.19 java                                                                                                                                    
11348 tomcat    20   0 9184m 5.6g 2808 S    1 71.3 642:25.41 java                                                                                                                                    
    1 root      20   0 24324 1188  656 S    0  0.0   0:01.52 init                                                                                                                                    
    2 root      20   0     0    0    0 S    0  0.0   0:00.26 kthreadd             
...

डीएफ -> tmpfs

Filesystem                1K-blocks     Used Available Use% Mounted on
tmpfs                       1635684      272   1635412   1% /run

हमारे पास मुख्य समस्या है:

  • सर्वर में 8 जी भौतिक स्मृति है
  • सोलर का ढेर केवल 6 जी लेता है
  • स्वैप का 1.5 जी है
  • Swappiness = 0
  • ढेर खपत उचित रूप से सुरंग लगता है
  • सर्वर पर चल रहा है: केवल सोलर और कुछ निगरानी सामग्री
  • हमारे पास सही औसत प्रतिक्रिया समय है
  • कभी-कभी 20 सेकंड तक, हम लंबे समय तक विरामित होते हैं

मुझे लगता है कि विराम एक स्वैप ढेर पर एक पूर्ण जीसी सही हो सकता है?

इतनी स्वैप क्यों है?

मुझे यह भी सच में नहीं पता कि यह जेवीएम है जो सर्वर को स्वैप करता है या अगर यह कुछ छुपा हुआ है जिसे मैं नहीं देख सकता। शायद ओएस पेज कैश? लेकिन यह सुनिश्चित नहीं है कि ओएस पृष्ठ कैश प्रविष्टियां क्यों बनाएगा यदि यह स्वैप बनाता है।

मैं कुछ लोकप्रिय जावा आधारित स्टोरेज / नोएसक्यूएल जैसे लोचदार खोज, वोल्डमॉर्ट या कैसंड्रा में इस्तेमाल की जाने वाली mlockall चाल का परीक्षण करने पर विचार कर रहा हूं: चेक करें जेएमवी / सोलर को मैकॉल का उपयोग करके स्वैप न करें

संपादित करें:

यहां आप अधिकतम ढेर, प्रयुक्त ढेर (नीला), एक प्रयुक्त स्वैप (लाल) देख सकते हैं। ऐसा लगता है कि संबंधित है।

मैं ग्रेफाइट के साथ देख सकता हूं कि नियमित रूप से कई पारन्यू जीसी होते हैं। और कुछ सीएमएस जीसी हैं जो तस्वीर के ढेर संकेतक कमी के अनुरूप हैं।

विराम को ढेर के साथ सहसंबंधित प्रतीत नहीं होता है लेकिन नियमित रूप से 10:00 और 11:30 के बीच वितरित किया जाता है, इसलिए यह अनुमानित पैरान्यू जीसी से संबंधित हो सकता है।

लोड टेस्ट के दौरान मैं कुछ डिस्क गतिविधि देख सकता हूं और कुछ स्वैप आईओ गतिविधि भी देख सकता हूं जो परीक्षण समाप्त होने पर वास्तव में शांत होता है।


JVM इंस्टेंस के रनटाइम पैरामीटर की निगरानी (और आंशिक रूप से बदलने) का एक सुविधाजनक तरीका VisualVM है:

पुनश्च
(हटाया गया)

पीपीएस मुझे कुछ अन्य टूल याद आया जिसे मैंने कुछ समय पहले इस्तेमाल किया था: विजुअल जीसी । यह आपको दृष्टि से दिखाता है कि जेवीएम मेमोरी मैनेजमेंट के अंदर क्या होता है, यहां कुछ screenshots । बहुत शक्तिशाली, और इसे VisualVM में प्लगइन के साथ भी एकीकृत किया जा सकता है (VisualVM मुखपृष्ठ पर प्लगइन अनुभाग देखें)।

PPPS
We sometimes have anormaly long pauses, up to 20 seconds. [...] I guess the pauses could be a full GC on a swapped heap right?
हाँ, वह हो सकता है। गैर-स्वैप किए गए ढेर पर भी लंबे समय तक जीसी पूरी तरह से हो सकता है। विजुअलVM के साथ आप निगरानी कर सकते हैं कि ~ 20sec विराम होने के समय एक पूर्ण जीसी होता है या नहीं। मैं अतिरिक्त लोड के साथ माप को गलत साबित करने के लिए, किसी अन्य होस्ट पर VisualVM चलाने और स्पष्ट जेएमएक्स के माध्यम से अपने वर्चुअल सर्वर पर JVM प्रक्रिया से कनेक्ट करने का सुझाव देता हूं। आप उस सेटअप को दिनों / हफ्तों में चल सकते हैं और इसलिए घटना पर निश्चित जानकारी इकट्ठा कर सकते हैं।

वर्तमान जानकारी के साथ अफैक्स, फिलहाल केवल इन संभावनाएं हैं:

  • देखा गया विराम पूर्ण जीसी के साथ एक साथ होता है: जेवीएम ठीक तरह से ट्यून नहीं किया जाता है। आप इसे जेवीएम पैरामीटर के माध्यम से कम कर सकते हैं, और शायद एक और जीसी एल्गोरिदम / इंजन चुन सकते हैं (क्या आपने सीएमएस और जी 1 जीसी की कोशिश की है? यह कैसे होता है इसके बारे में अधिक जानकारी उदाहरण के लिए)
  • मनाए गए विराम JVM में पूर्ण जीसी के साथ मेल नहीं खाते हैं: भौतिक वर्चुअल होस्ट कारण हो सकता है। अपने एसएलए को सत्यापित करें (वर्चुअल रैम में कितनी आभासी रैम की गारंटी है) और वर्चुअल सर्वर की निगरानी करने के लिए अपने सेवा प्रदाता से संपर्क करें।

मुझे यह उल्लेख करना चाहिए था कि विजुअलVM को जावा के साथ भेज दिया गया है। और जेकोनसोल, जावा के साथ भी भेज दिया गया है, जो विजुअलVM से हल्का और अधिक कॉम्पैक्ट है (लेकिन इसमें कोई प्लगइन्स नहीं है, कोई प्रोफाइलिंग नहीं है), लेकिन एक समान सिंहावलोकन प्रदान करता है।

यदि VisualVM / JConsole / VisualGC के लिए जेएमएक्स कनेक्शन स्थापित करना इस पल के लिए बहुत जटिल है, तो आप फॉलोउन जावा पैरामीटर का सहारा ले सकते हैं: -XX:+PrintGC -XX:+PrintGCTimeStamps -Xloggc:/my/log/path/gclogfile.log । ये पैरामीटर JVM को निर्दिष्ट लॉग फ़ाइल को प्रत्येक जीसी रन के लिए एक प्रविष्टि लिखने का कारण बनेंगे। यह विकल्प दीर्घकालिक विश्लेषण के लिए भी उपयुक्त है, और शायद आपके जेवीएम पर कम से कम ओवरहेड वाला है।

अपने प्रश्न के बारे में फिर से (और फिर) सोचने के बाद: यदि आपको आश्चर्य है कि अतिरिक्त 3+ जीबी कहां से आती है, तो यहां एक संबंधित प्रश्न है । मैं व्यक्तिगत रूप से अंगूठे के नियम के रूप में कारक x1.5 का उपयोग करता हूं।


आपका ढेर वास्तव में 6.5 जीबी वर्चुअल मेमोरी का उपयोग कर रहा है (इसमें परम जीन शामिल हो सकता है)

आपके पास 64 एमबी ढेर का उपयोग कर धागे का एक गुच्छा है। स्पष्ट नहीं है कि कुछ क्यों हैं और अन्य डिफ़ॉल्ट 1 एमबी का उपयोग कर रहे हैं।

कुल 9.3 मिलियन केबी वर्चुअल मेमोरी है। मैं केवल निवासी आकार के बारे में चिंता करता हूँ।

प्रक्रिया के निवासी आकार को खोजने के लिए top का उपयोग करने का प्रयास करें।

आप इस कार्यक्रम को उपयोगी पा सकते हैं

    BufferedReader br = new BufferedReader(new FileReader("C:/dev/gistfile1.txt"));
    long total = 0;
    for(String line; (line = br.readLine())!= null;) {
        String[] parts = line.split("[- ]");
        long start = new BigInteger(parts[0], 16).longValue();
        long end = new BigInteger(parts[1], 16).longValue();
        long size = end - start + 1;
        if (size > 1000000)
            System.out.printf("%,d : %s%n", size, line);
        total += size;
    }
    System.out.println("total: " + total/1024);

जब तक आपके पास स्मृति का उपयोग करके जेएनआई लाइब्रेरी न हो, मेरा अनुमान है कि आपके पास बहुत सारे थ्रेड हैं जिनमें प्रत्येक का अपना स्टैक स्पेस है। मैं आपके पास धागे की संख्या की जांच करूंगा। आप प्रति थ्रेड अधिकतम स्टैक स्पेस को कम कर सकते हैं, लेकिन आपके पास मौजूद थ्रेड की संख्या को कम करने के लिए एक बेहतर विकल्प हो सकता है।

ऑफ़ हेप मेमोरी परिभाषा अप्रबंधित है, इसलिए इसे आसानी से "ट्यून" नहीं किया जाता है। ढेर को ट्यून करना भी आसान नहीं है।

64-बिट JVMs पर डिफ़ॉल्ट स्टैक आकार 1024K है, इसलिए 700 थ्रेड वर्चुअल मेमोरी के 700 एमबी का उपयोग करेंगे।

आपको निवासी स्मृति आकारों के लिए वर्चुअल मेमोरी आकार को भ्रमित नहीं करना चाहिए। 64-बिट एप्लिकेशन पर वर्चुअल मेमोरी लगभग निःशुल्क है और यह केवल निवासी आकार है जिसके बारे में आपको चिंता करनी चाहिए।

जिस तरह से मैं इसे देखता हूं आपके पास 9.3 जीबी कुल है।

  • 6.0 जीबी ढेर।
  • 128 एमबी परम जीन
  • 700 एमबी ढेर।
  • <250 साझा पुस्तकालयों
  • 2.2 जीबी अज्ञात (मुझे वर्चुअल मेमोरी निवासी स्मृति नहीं है)

आखिरी बार किसी को यह समस्या थी, उनके पास उनके मुकाबले बहुत अधिक धागे थे। मैं आपके पास अधिकतम थ्रेड की जांच करता हूं क्योंकि यह चरम आकार निर्धारित करता है। उदाहरण के लिए 3000 के करीब था?

इन जोड़ों में से प्रत्येक हम्म एक धागा है।

7f0cffddf000-7f0cffedd000 rw-p 00000000 00:00 0 
7f0cffedd000-7f0cffee0000 ---p 00000000 00:00 0

और ये सुझाव देते हैं कि अब आपके पास 700 से कम धागे हैं .....







jvm