क्या आदिम का जावा सरणी ढेर या ढेर में संग्रहीत है?


85

मेरे पास इस तरह की एक घोषणा है:

int a[];

यहाँ aआदिम intप्रकार की एक सरणी है । यह सरणी कहाँ संग्रहीत है? क्या यह ढेर या ढेर पर संग्रहीत है? यह एक intआदिम प्रकार है, सभी आदिम प्रकार ढेर पर संग्रहीत नहीं हैं।


38
यह एक सरणी नहीं है। यह एक सरणी का संदर्भ है। यदि यह एक विधि का एक स्थानीय चर है, तो यह संदर्भ ही ढेर पर संग्रहीत किया जा सकता है यदि यह एक वर्ग या वस्तु का सदस्य है, या स्टैक पर है। और आदिम प्रकार ढेर पर संग्रहीत किए जा सकते हैं यदि वे किसी वर्ग या वस्तु के सदस्य हों।
चाचा

जवाबों:


143

जैसा कि गुरुकुलकी ने कहा, यह ढेर पर जमा है। हालाँकि, आपकी पोस्ट ने किसी गलत इरादे वाले व्यक्ति द्वारा मिथक का प्रचार करने के कारण शायद गलतफहमी का सुझाव दिया कि "आदिम हमेशा ढेर पर रहते हैं"। यह असत्य है। स्थानीय चर के ढेर पर उनके मूल्य हैं, लेकिन सभी आदिम चर स्थानीय नहीं हैं ...

उदाहरण के लिए, इस पर विचार करें:

public class Foo
{
    int value;
}
...

public void someOtherMethod()
{
    Foo f = new Foo();
    ...
}

अब, कहाँ f.valueरहता है? मिथक यह स्टैक पर सुझाएगा - लेकिन वास्तव में यह नई Fooवस्तु का हिस्सा है , और ढेर 1 पर रहता है । (ध्यान दें कि fस्वयं का मूल्य एक संदर्भ है, और स्टैक पर रहता है।)

वहाँ से, यह सरणियों के लिए एक आसान कदम है। आप एक सरणी के बारे में सोच सकते हैं जैसे कि बस बहुत सारे चर होते हैं - इसलिए new int[3]इस फॉर्म का एक वर्ग होने जैसा है:

public class ArrayInt3
{
    public readonly int length = 3;
    public int value0;
    public int value1;
    public int value2;
}

1 वास्तव में, यह इससे अधिक जटिल है। स्टैक / हीप डिस्टिंक्शन ज्यादातर एक कार्यान्वयन विवरण है - मेरा मानना ​​है कि कुछ JVM, संभवतः प्रयोगात्मक वाले, बता सकते हैं कि कोई वस्तु कभी किसी विधि से "पलायन" नहीं करती है, और स्टैक पर पूरी वस्तु को आवंटित कर सकती है। हालाँकि, यह वैचारिक रूप से ढेर पर है, अगर आप देखभाल करना चुनते हैं।


1
जावा में "एस्केप एनालिसिस" के बारे में: blog.juma.me.uk/2008/12/17/objects-with-no-allocation-overhead यह कहता है कि यह JDK 6 अपडेट 14 की प्रारंभिक पहुँच रिलीज़ के बाद से मौजूद है, और JDK 6 अपडेट 23 के बाद से डिफ़ॉल्ट रूप से सक्षम है।
गुइडो

क्या यह कुछ भी बदलता है अगर सरणी सार्वजनिक स्थिर अंतिम है? क्या यह निरंतर पूल का हिस्सा नहीं होना चाहिए?
मलयासीज

@ मालचीज़: नहीं। एक सरणी कभी एक स्थिर नहीं होती है।
जॉन स्कीट

@JonSkeet: जावा लाइब्रेरी के सभी संस्करणों में, जिनके बारे में मुझे पता है, हर Stringएक द्वारा समर्थित है char[]। मेरा मानना ​​है कि शाब्दिक तार सार्वजनिक स्थिर पूल में संग्रहीत किए जाते हैं; जीसी ऑप्टिमाइज़ेशन के लिए, इसका अर्थ यह होगा कि बैकिंग सरणियों को इसी तरह संग्रहित किया जाना चाहिए (अन्यथा निरंतर जीसी को किसी भी जीसी चक्र के दौरान स्कैन करना होगा जहां बैकिंग सरणी अन्यथा संग्रह के लिए योग्य होगी)।
सुपरकाट

@ सुपरकैट: हाँ, यह समझ में आएगा। लेकिन आप जिस भी ऐरे से खुद को घोषित करते हैं , वह निरंतर पूल के हिस्से के रूप में समाप्त नहीं होता है।
जॉन स्कीट

37

यह ढेर पर संग्रहीत किया जाएगा

क्योंकि सरणी जावा में एक वस्तु है।

संपादित करें : यदि आपके पास है

int [] testScores; 
testScores = new int[4];

इस कोड को कंपाइलर से यह कहते हुए सोचें, "एक एरे ऑब्जेक्ट बनाएं, जो चार इन्टल्स रखेगा, और इसे नामांकित संदर्भ वेरिएबल में असाइन करेगा testScores। इसके अलावा, आगे बढ़ें और प्रत्येक intएलिमेंट को शून्य पर सेट करें । धन्यवाद।"


2
और testScores नाम का संदर्भ चर (ढेर पर सरणी की ओर इशारा करते हुए) स्टैक पर होगा।
जकी

11
यदि आप -gसंकलक के लिए विकल्प की आपूर्ति करते हैं तो कोड केवल "धन्यवाद" कहता है । अन्यथा इसे दूर किया जाएगा।
भीड़

1
@ mob आप एक धारणा बना रहे हैं कि यह एकमात्र कोड है। यह मान लेना बेहतर है कि ये दो लाइनें एक बड़े कार्यक्रम का हिस्सा हैं जो वास्तव में सरणी का उपयोग करती हैं।
कोड-अपरेंटिस

22

यह आदिम प्रकार की एक सरणी है जो अपने आप में आदिम नहीं है। अंगूठे का एक अच्छा नियम है जब नया कीवर्ड शामिल होता है तो परिणाम ढेर पर होगा।


18

मैं सिर्फ इस विषय पर कुछ परीक्षण साझा करना चाहता था।

आकार की संख्या 10 मिलियन

public static void main(String[] args) {
    memInfo();
    double a[] = new double[10000000];
    memInfo();
}

आउटपुट:

------------------------
max mem = 130.0 MB
total mem = 85.0 MB
free mem = 83.6 MB
used mem = 1.4 MB
------------------------
------------------------
max mem = 130.0 MB
total mem = 130.0 MB
free mem = 48.9 MB
used mem = 81.1 MB
------------------------

जैसा कि आप देखते हैं कि उपयोग किया गया ढेर का आकार ~ 80 एमबी है, जो कि 10 मीटर * आकार का (डबल) है।

लेकिन अगर हमारे पास डबल के बजाय डबल का उपयोग होता है

public static void main(String[] args) {
    memInfo();
    Double a[] = new Double[10000000];
    memInfo();
}

आउटपुट 40MB दिखाएगा। हमारे पास केवल डबल संदर्भ हैं, वे आरंभिक नहीं हैं।

इसे डबल से भरना

public static void main(String[] args) {
    memInfo();
    Double a[] = new Double[10000000];      
    Double qq = 3.1d;
    for (int i = 0; i < a.length; i++) {
        a[i] = qq;
    }
    memInfo();
}

फिर भी 40 एमबी। क्योंकि वे सभी एक ही डबल ऑब्जेक्ट की ओर इशारा करते हैं।

इसके बजाय डबल के साथ प्रारंभ करना

public static void main(String[] args) {
    memInfo();
    Double a[] = new Double[10000000];
    Double qq = 3.1d;
    for (int i = 0; i < a.length; i++) {
        a[i] = qq.doubleValue();
    }
    memInfo();
}

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

लाइन

a[i] = qq.doubleValue();

के बराबर है

a[i] = Double.valueOf(qq.doubleValue());

जो के बराबर है

a[i] = new Double(qq.doubleValue());

चूंकि हम हर बार नई डबल ऑब्जेक्ट बनाते हैं, हम ढेर को उड़ा देते हैं। इससे पता चलता है कि डबल क्लास के अंदर मान ढेर में जमा हैं।


1
क्या आप मेमोइन्फो () pls का कोड विवरण पेस्ट कर सकते हैं? :)
हेडलीयन

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.