java - क्या OpenJDK JVM कभी भी ढेर मेमोरी को लिनक्स में वापस देगी?



memory-management heap-memory (1)

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

आमतौर पर, इस तरह के सवालों का स्वीकृत जवाब -XX:MaxHeapFreeRatio का उपयोग -XX:MaxHeapFreeRatio और -XX:MinHeapFreeRatio । (उदाहरण 1 , 2 , 3 , 4 )। लेकिन हम इस तरह जावा चला रहे हैं:

java -Xmx4G -XX:MaxHeapFreeRatio=50 -XX:MinHeapFreeRatio=30 MemoryUsage

और अभी भी VisualVM में इसे देखें:

1

स्पष्ट रूप से, JVM सम्मान नहीं दे रहा है -XX:MaxHeapFreeRatio=50 रूप में heapFreeRatio 100% के बहुत करीब है और कहीं भी 50% के पास नहीं है। OS पर "Perform GC" रिटर्न मेमोरी पर क्लिक करने की कोई राशि नहीं है।

MemoryUsage.java:

import java.util.ArrayList;
import java.util.List;

public class MemoryUsage {

    public static void main(String[] args) throws InterruptedException {
        System.out.println("Sleeping before allocating memory");
        Thread.sleep(10*1000);

        System.out.println("Allocating/growing memory");
        List<Long> list = new ArrayList<>();
        // Experimentally determined factor. This gives approximately 1750 MB
        // memory in our installation.
        long realGrowN = 166608000; //
        for (int i = 0 ; i < realGrowN ; i++) {
            list.add(23L);
        }

        System.out.println("Memory allocated/grown - sleeping before Garbage collecting");
        Thread.sleep(10*1000);

        list = null;
        System.gc();

        System.out.println("Garbage collected - sleeping forever");
        while (true) {
            Thread.sleep(1*1000);
        }
    }
}

संस्करण:

> java -version
openjdk version "1.8.0_66-internal"
OpenJDK Runtime Environment (build 1.8.0_66-internal-b01)
OpenJDK 64-Bit Server VM (build 25.66-b01, mixed mode)

> uname -a
Linux londo 3.16.0-4-amd64 #1 SMP Debian 3.16.7-ckt11-1+deb8u5 (2015-10-09) x86_64 GNU/Linux

> lsb_release -a
No LSB modules are available.
Distributor ID: Debian
Description:    Debian GNU/Linux 8.2 (jessie)
Release:    8.2
Codename:   jessie

मैंने ओपनजेडके 1.7 और सन जावा के 1.8 की भी कोशिश की है। सभी समान व्यवहार करते हैं और कोई भी ओएस को वापस मेमोरी नहीं देता है।

मुझे लगता है कि मुझे इसकी आवश्यकता है और यह स्वैप और पेजिंग "इसे" हल नहीं करेगा, क्योंकि डिस्क आईओ को 2GB कचरा के अंदर और बाहर पेजिंग पर खर्च करना सिर्फ संसाधनों की बर्बादी है। यदि आप असहमत हैं, तो कृपया मुझे बताएं।

मैंने मॉलॉक malloc() / free() साथ थोड़ा मेमोरीयूजेज सी भी लिखा है, और यह ओएस को मेमोरी वापस करता है । तो यह सी में संभव है। शायद जावा के साथ नहीं?

संपादित करें: अगस्टो ने बताया कि खोज ने मुझे -XX:MaxHeapFreeRatio पर ले -XX:MaxHeapFreeRatio और -XX:MinHeapFreeRatio केवल -XX:+UseSerialGC साथ काम किया। मैं खुश था और यह कोशिश की, हैरान था कि मुझे यह नहीं मिला। हां, इसने मेरे मेमोरीयूज.जावा के साथ काम किया:

हालाँकि, जब मैंने कोशिश की -XX:+UseSerialGC हमारे असली ऐप के साथ, इतना नहीं:

मुझे पता चला कि जीसी () ने थोड़ी देर बाद मदद की, इसलिए मैंने एक ऐसा धागा बनाया जो कम या ज्यादा किया:

while (idle() && memoryTooLarge() && ! tooManyAttemptsYet()) {
    Thread.sleep(10*1000);
    System.gc();
}

और यह चाल चली:

मैंने वास्तव में -XX:+UseSerialGC साथ व्यवहार को पहले देखा था -XX:+UseSerialGC और multiple System.gc() मेरे कई प्रयोगों में से कुछ में कॉल करता है, लेकिन जीसी थ्रेड की आवश्यकता को पसंद नहीं किया। और कौन जानता है कि अगर यह हमारे ऐप और जावा दोनों के रूप में काम करना जारी रखेगा। इसके लिए अवश्य ही एक बेहतर तरीका होना चाहिए। '

वह कौन सा तर्क है जो मुझे System.gc() चार बार (लेकिन तुरंत नहीं System.gc() कॉल करने के लिए मजबूर करता है, और यह सामान कहां से प्रलेखित है?

-XX:MaxHeapFreeRatio लिए प्रलेखन की खोज में -XX:MaxHeapFreeRatio और -XX:MinHeapFreeRatio केवल -XX:MinHeapFreeRatio साथ काम कर रहा है -XX:+UseSerialGC , मैंने जावा उपकरण / निष्पादन योग्य के लिए दस्तावेज़ीकरण पढ़ा और यह कहीं भी उल्लेख नहीं किया गया है कि -XX:MaxHeapFreeRatio और -XX:MinHeapFreeRatio केवल -XX:+UseSerialGC साथ काम करता है -XX:+UseSerialGC । वास्तव में, फिक्स्ड मुद्दा [JDK-8028391] न्यूनतम / MaxHeapFreeRatio झंडे को प्रबंधित करने योग्य बनाएं :

अनुप्रयोगों को कैसे और कब कम या अधिक GC के लिए अनुमति देने के लिए सक्षम करने के लिए, झंडे -XX: MinHeapFreeRatio और -XX: MaxHeapFreeRatio को प्रबंधनीय बनाया जाना चाहिए। इन झंडों के लिए समर्थन को डिफ़ॉल्ट समानांतर कलेक्टर में भी लागू किया जाना चाहिए।

निश्चित मुद्दे के लिए एक comment कहती है:

इन झंडों के लिए अनुकूली आकार नीति के भाग के रूप में ParallelGC को भी जोड़ा गया है।

मैंने जाँच की है, और Openjdk-8 के लिए वापस तय किए गए निश्चित मुद्दे में संदर्भित patch वास्तव में Openjdk-8 संस्करण का उपयोग कर रहा है, जो कि स्रोत पैकेज टैरबॉल में निहित है। तो यह स्पष्ट रूप से "डिफ़ॉल्ट समानांतर कलेक्टर" में काम करना चाहिए, लेकिन जैसा कि मैंने इस पोस्ट में दिखाया है। मुझे अभी तक कोई दस्तावेज नहीं मिला है जो कहता है कि यह केवल -XX:+UseSerialGC साथ काम करना चाहिए। और जैसा कि मैंने यहां दस्तावेज किया है, यहां तक ​​कि यह अविश्वसनीय / पासा है।

क्या मैं सिर्फ -XX:MaxHeapFreeRatio नहीं ले -XX:MaxHeapFreeRatio और -XX:MinHeapFreeRatio वे सभी हुप्स के माध्यम से जाने के बिना क्या वादा करते हैं?


G1 (-XX: + UseG1GC), समानांतर स्कैवेंज (-XX: + UseParallelGC) और पैरेललओल्ड (-XX: + UseParallelOldGC) हीप मेमोरी के सिकुड़ने पर वापसी करते हैं। मैं सीरियल और सीएमएस के बारे में निश्चित नहीं हूं, उन्होंने मेरे प्रयोगों में अपने ढेर को छोटा नहीं किया।

दोनों समानांतर कलेक्टरों को ढेर को "स्वीकार्य" आकार तक सिकुड़ने से पहले कई GCs की आवश्यकता होती है। यह प्रति डिजाइन है। वे जानबूझकर ढेर पर पकड़ रहे हैं यह मानते हुए कि भविष्य में इसकी आवश्यकता होगी। झंडे को स्थापित करना -XX: GCTimeRatio = 1 स्थिति को कुछ हद तक सुधार देगा लेकिन इसमें अभी भी कई जीसीएस को हटना होगा।

तेजी से सिकुड़ते हुए G1 उल्लेखनीय रूप से अच्छा है, इसलिए ऊपर वर्णित usecase के लिए मैं कहूंगा कि यह G1 और रनिंग System.gc() का उपयोग करके हल कर सकता है System.gc() सभी कैश और क्लास लोडर आदि जारी करने के बाद System.gc()

http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6498735





heap-memory