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




memory-management heap-memory (3)

यदि विधि है (एम 1 () कहें) जो आपके आवेदन में भारी भारोत्तोलन करता है तो आप इसे आजमा सकते हैं:

  1. एम 1 () को कॉल करने के बजाय, काम करने के तरीके के लिए आवश्यक सभी वस्तुओं को serialize
  2. एक मुख्य विधि बनाएं जो आपके द्वारा पिछले चरण में क्रमबद्ध वस्तुओं को de-serialize करें। और एम 1 () कहते हैं - यह मुख्य विधि प्रोग्राम पी 1 के लिए प्रवेश बिंदु है।
  3. एम 1 () के पूरा होने पर, मुख्य कार्यक्रम के आउटपुट को डी-सीरियलाइज करने के लिए क्रमबद्ध करें।
  4. Runtime or ProcessBuilder का उपयोग कर पी 1 को एक अलग प्रोग्राम के रूप में निष्पादित करें।

इस तरह जब भारी उठाने की विधि m1 () पूर्ण हो जाती है, तो प्रक्रिया P1 समाप्त हो जाएगी, जो उस JVM पर ढेर को छोड़ देना चाहिए।

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

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

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

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

1

जाहिर है, JVM सम्मान नहीं कर रहा है -XX:MaxHeapFreeRatio=50 रूप में हीपफ्रीरेटियो 100% के करीब है और कहीं भी 50% के करीब नहीं है। "प्रदर्शन जीसी" पर क्लिक करने की कोई मात्रा ओएस को स्मृति रिटर्न नहीं देती है।

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 भी कोशिश की है। सभी समान व्यवहार करते हैं और कोई भी ओएस को स्मृति नहीं देता है।

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

मैंने malloc() / free() साथ एक छोटी स्मृति Usage.c भी लिखा है, और यह ओएस को स्मृति लौटाता है। तो सी में संभव है शायद जावा के साथ नहीं?

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

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

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

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

और यह चाल है:

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

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

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

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

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

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

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

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


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


"जी 1 (-XX: + यूज जी 1 जीसी), समांतर स्वेवेंग (-XX: + यूजपेरेलग जीसी) और समानांतर (-XX: + UseParallelOldGC) ढेर को कम करने पर स्मृति लौटाते हैं। मुझे सीरियल और सीएमएस के बारे में इतना यकीन नहीं है, उन्होंने ' मेरे प्रयोगों में उनके ढेर को कम नहीं करते हैं।

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

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

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







heap-memory