2016-02-23 7 views
61

इस प्रश्न को शायद उत्तर देने के लिए कुछ कंपाइलर ज्ञान की आवश्यकता होगी। मैं वर्तमान में एक परियोजना पर काम कर रहा हूँ जहाँ मैं एक सरणी हो सकता है कि बनाने वाले हैं या तोक्या जावा में int [big] [small] या int [small] [big] के बीच कोई निम्न-स्तर अंतर है?

int[2][veryLargeNumber] 

या

int [veryLargeNumber][2] 

यह कोई फर्क नहीं तार्किक बनाता है, लेकिन मैं सोच रहा था कि फार्म (और इसलिए बड़े आकार) स्मृति में भिन्न हो सकता है (शायद सवाल होना चाहिए, क्या कंप्यूटर्स चतुर हैं जो उन्हें सूट करने के लिए सरणी को पुनर्व्यवस्थित करने के लिए पर्याप्त हैं)?

+2

ऐसा लगता है कि पहला विकल्प कम ओवरहेड होगा, क्योंकि यह दो बड़े 1 डी सरणी के बराबर है, जबकि दूसरा विकल्प बड़ी संख्या में छोटे 1 डी सरणी के बराबर है। पहले विकल्प को कम सरणी उदाहरणों की आवश्यकता होती है - 2 डी सरणी और 2 1-डी सरणी। दूसरे विकल्प के लिए 2 डी सरणी उदाहरण और कई 1-डी सरणी उदाहरणों की आवश्यकता होती है। – Eran

+0

मुझे विश्वास नहीं है कि एक है, नहीं। वहाँ होगा अगर दूसरा आयाम निर्दिष्ट नहीं किया गया था, लेकिन यहां आप इसे निर्दिष्ट करते हैं। – fge

+2

@ वास्तव में ईरान नहीं; यह 'multianewarray' है जिसका उपयोग तब किया जाता है जब आपके पास "निश्चित आयाम" एकाधिक सरणी – fge

उत्तर

53

जावा केवल वास्तव में एकल आयामी सरणी लागू करता है। इसमें बहु-आयामी प्रकार हैं, हालांकि दो आयामी सरणी वास्तव में सरणी की सरणी के रूप में लागू की जाती हैं। प्रत्येक सरणी में लगभग 16 बाइट्स का ओवरहेड होता है। ओवरहेड को कम करने के लिए आप int[2][x] के साथ बेहतर हैं।

आप इस समस्या को पूरी तरह से सहायक तरीकों का उपयोग करके टालना कर सकते हैं।

final int[] array = new int[2 * veryLargeNumber]; 

public int get(int x, int y) { 
    return array[idx(x, y)]; 
} 

public void set(int x, int y, int val) { 
    array[idx(x, y)] = val; 
} 

private int idx(int x, int y) { 
    return x * 2 + y; // or x * veryLargeNumber + y; 
} 

एक अनूठा प्रत्येक वस्तु हैश खुद को यह प्रदान करते हैं, जो अपनी वस्तु शीर्षक में संग्रहीत किया जाता है hashCode उत्पन्न करने के लिए।

आप http://ideone.com/oGbDJ0 से देख सकते हैं कि प्रत्येक नेस्टेड सरणी स्वयं में एक वस्तु है।

int[][] array = new int[20][2]; 
for (int[] arr : array) { 
    System.out.println(arr); 
} 

एक int[] जो [I@ hashCode() शीर्षक में संग्रहीत के बाद उसके बाद के आंतरिक प्रतिनिधित्व प्रिंट करता है। यह कुछ विश्वास नहीं है, वस्तु का पता। पता, hashCode के रूप में इस्तेमाल नहीं किया जा सकता के रूप में वस्तु जीसी द्वारा किसी भी समय ले जाया जा सकता है (जब तक आप एक JVM जो वस्तुओं कभी नहीं ले जाता है)

[[email protected] 
[[email protected] 
[[email protected] 
[[email protected] 
[[email protected] 
[[email protected] 
[[email protected] 
[[email protected] 
[[email protected] 
[[email protected] 
[[email protected] 
[[email protected] 
[[email protected] 
[[email protected] 
[[email protected] 
[[email protected] 
[[email protected] 
[[email protected] 
[[email protected] 
[[email protected] 

आप देख सकते हैं कितना स्मृति अगर प्रयोग किया जाता है आप -XX:-UseTLAB https://github.com/peter-lawrey/Performance-Examples/blob/master/src/main/java/vanilla/java/memory/ArrayAllocationMain.java

public static void main(String[] args) { 

    long used1 = memoryUsed(); 
    int[][] array = new int[200][2]; 

    long used2 = memoryUsed(); 
    int[][] array2 = new int[2][200]; 

    long used3 = memoryUsed(); 
    if (used1 == used2) { 
     System.err.println("You need to turn off the TLAB with -XX:-UseTLAB"); 
    } else { 
     System.out.printf("Space used by int[200][2] is " + (used2 - used1) + " bytes%n"); 
     System.out.printf("Space used by int[2][200] is " + (used3 - used2) + " bytes%n"); 
    } 
} 

public static long memoryUsed() { 
    Runtime rt = Runtime.getRuntime(); 
    return rt.totalMemory() - rt.freeMemory(); 
} 

प्रिंट

Space used by int[200][2] is 5720 bytes 
Space used by int[2][200] is 1656 bytes 
+0

एरर संख्या का तीसरा पैराग्राफ देखें। 'multianewarray': पी – fge

+0

@ फ़ेज जावा में बहु-आयामी प्रकार हैं, हालांकि यह अभी भी सरणी की एक सरणी है और उन घोंसले वाले सरणी में ऑब्जेक्ट हेडर अन्य सभी ऑब्जेक्ट्स की तरह है। –

+6

एक अन्य दिलचस्प बिंदु प्रदर्शन हो सकता है, यदि आपके पास वास्तव में बड़ी सरणी है और इसे एक तंग लूप में एक्सेस किया गया है, तो स्मृति क्षेत्र एक समस्या हो सकती है। इस मामले के लिए (यदि कोई प्रोफाइलर आपको दिखाता है कि एक प्रदर्शन बाधा है) तो आप तत्वों की व्यवस्था कर सकते हैं ताकि उन्हें लगातार उपयोग किया जा सके। (जो आपके नियंत्रण प्रवाह के आधार पर x * 2 + y या y * length + x हो सकता है। – Falco

23

दिलचस्प सवाल के साथ TLAB बंद कर देते हैं, मैं एक साधारण प्रोग्राम भाग गया

int N = 100000000; 
long start = System.currentTimeMillis(); 
int[][] a = new int[2][N]; 
System.out.println(System.currentTimeMillis() - start + " ms"); 

जिसके परिणामस्वरूप 160 ms हुआ। फिर मैंने दूसरे संस्करण

int N = 100000000; 
long start = System.currentTimeMillis(); 
int[][] a = new int[N][2]; 
System.out.println(System.currentTimeMillis() - start + " ms"); 

जिसके परिणामस्वरूप 30897 ms हुआ। तो वास्तव में पहला विकल्प बहुत बेहतर लगता है।

+0

वह यह पूछ रहा है कि जेएनडीआई में इसे कैसे कार्यान्वित किया जाता है, यह समझने के लिए कि कौन सा उपयोग करने योग्य कोड है ?? यह वह जवाब नहीं है जिसे उसने पूछा .. –

+6

@V IikrantKashyap ईमानदार होने के लिए, मुझे लगता है कि यह एक दिलचस्प प्रदर्शन अवलोकन है। और जब वह सीधे अपने प्रश्न का उत्तर नहीं दे सकता है, तो यह तय करने में मदद कर सकता है कि किस तरह से जाना है। – radoh

+0

दिलचस्प, शेर आलम जवाब आपके समर्थन का समर्थन करता है। –

11
int[2][veryLargeNumber] 

जबकि

int[veryLargeNumber][2] 


आइटम की verlarnumber साथ दो सरणियों दो आइटम होने सरणियों के verylargenumber बनाता है बनाता है।

नोट: सरणी निर्माण का ओवरहेड है। इसलिए पहले एक

+6

इसके अलावा, दूसरा विकल्प अधिक मेमोरी विखंडन का कारण बनता है। स्मृति में यादृच्छिक स्थानों तक पहुंच धीमा है। – Nayuki

+2

यह स्पष्ट और सबसे सीधे बिंदु उत्तर के लिए है। –

1

कम से कम int[2][veryLargeNumber] बेहतर दृष्टिकोण है।

पीटर (int[] array = new int[2 * veryLargeNumber];) ने सुझाव दिया एक और भी बेहतर है, या यदि स्मृति आपकी समस्या है, तो आप देशांतर पूर्णांकों (long[] array = new long[veryLargeNumber];) और बिटवाइज़ ऑपरेटर्स के बजाय बेहतर अभी तक, उपयोग कैशिंग जब भी संभव हो उपयोग कर सकते हैं, या।

सावधान रहें! अधिकांश जेडीके/जेआरई वितरण में सूर्य [[email protected] (सूर्य का & ओरेकल) System.identityHashCode() द्वारा दिया गया है और यह की गारंटी नहीं है प्रत्येक ऑब्जेक्ट के लिए अद्वितीय है। तो आप सरणी ऑब्जेक्ट की यूनिकिटी की जांच करने के लिए System.out.println(array); पर भरोसा नहीं कर सकते हैं।

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