2013-03-11 15 views
10

a और b के लिए कितने बाइट आवंटित किए जाएंगे?क्या बहुआयामी सरणी की घोषणा में आदेश का उपयोग स्मृति पर प्रभाव पड़ता है?

import android.graphics.Bitmap; 

Bitmap[][][] a = new Bitmap[1000][2][2]; 
Bitmap[][][] b = new Bitmap[2][2][1000]; 

ध्यान दें कि मैं केवल शुद्ध सरणी द्वारा ली गई स्मृति के बारे में पूछ रहा हूं, अंदर कोई वस्तु नहीं है।

मैं क्यों पूछ रहा हूं? क्योंकि मैं एक एंड्रॉइड गेम लिख रहा हूं। मेरे लिए आदेश कोई फर्क नहीं पड़ता, लेकिन अगर कोई स्मृति अंतर है, तो कुछ को बचाने के लिए अच्छा होगा।

उत्तर

10

हां इससे कोई फर्क पड़ता है।

जावा में, 2 डी सरणी 1 डी सरणी की एक सरणी है, और सरणी (सभी ऑब्जेक्ट्स की तरह) में तत्वों को स्वयं रखने के लिए आवश्यक स्थान के अतिरिक्त शीर्षलेख होते हैं।

तो int[10][2] बनाम int[2][10] पर विचार करें, और 32 बिट जेवीएम मानें।

  • int[2][10] में 2 तत्वों की एक सरणी और 10 तत्वों के 2 सरणी शामिल हैं। कुल - 3 सरणी वस्तुओं + 22 तत्व।
  • int[10][2] में 10 तत्वों की एक सरणी और 2 तत्वों के 10 सरणी शामिल हैं। कुल - 11 सरणी वस्तुओं + 30 तत्व।

अगर हम मान लेते हैं कि शीर्ष लेख का आकार 3 32 बिट शब्द (एक 32bit JVM के लिए विशिष्ट) और एक संदर्भ है 1 32 बिट शब्द, तो

  • int[2][10] लेता है 3 * 3 + 22 है * 1 = 31 शब्द = 124 बाइट्स
  • int[10][2] 11 * 3 + 30 * 1 = 63 शब्द = 252 बाइट्स
  • लेता

यही तर्क लागू करें और आप आयामों की अधिक संख्या के सरणियों के आकार का अनुमान कर सकते हैं।

लेकिन यह स्पष्ट है कि यदि आप सबसे बड़ा आयाम सही है तो आप कम जगह का उपयोग करते हैं।


मैं int सरणियों के साथ गणित किया है, लेकिन एक 32 बिट मशीन पर एक int और एक reference बाइट्स की एक ही नंबर पर कब्जा। एक 64 बिट मशीन पर, एक संदर्भ int या long के समान आकार के समान हो सकता है, JVM विकल्पों के आधार पर। हेडर आकार भी अलग हो सकते हैं .... बिल्कुल सही नहीं ... संभावित रूप से प्लेटफार्म निर्भर है।

मैंने Bitmap वस्तुओं को स्वयं रखने के लिए आवश्यक स्थान के लिए जिम्मेदार नहीं ठहराया है, लेकिन यह वही है जब आप सरणी व्यवस्थित करते हैं।

+0

धन्यवाद! मेरा एक सवाल है। हो सकता है कि स्मृति को सहेजने का सबसे अच्छा तरीका 'बिटमैप [] सी = नया बिटमैप [2 * 1000] 'और बाद में सूचकांक की तरह' 1000 * i + j' होगा? 'बिटमैप [2] [1000]' की तुलना में कोई गति अंतर नहीं होगा? –

+1

1) हां ... हालांकि यह आपके कोड को पढ़ने के लिए कठिन बनाता है और वृद्धिशील बचत बहुत अच्छी नहीं है। 2) एक 1 डी सरणी * हो सकता है * तेज हो क्योंकि कम सरणी सीमाएं और कम fetches हैं। हालांकि, अंतर में कोई अंतर बनाने के लिए अंतर बहुत छोटा है। –

+1

ध्यान दें कि उदाहरण के लिए 64 बिट हॉटस्पॉट पर, संदर्भ डिफ़ॉल्ट रूप से 4 बाइट्स पर संपीड़ित होते हैं। – assylias

-1

कोई मेमोरी अंतर नहीं है, लेकिन आपके सरणी सूचकांक का क्रम - सिद्धांत रूप में - आपके प्रोग्राम की गति पर प्रभाव डाल सकता है।

आप आमतौर पर नेस्टेड लूप में बहु-आयामी सरणी सामग्री को संसाधित करते हैं। इसलिए आपके सरणी को इस तरह व्यवस्थित किया जाना चाहिए कि आप अपने आंतरिक लूप में आसन्न तत्वों को संबोधित करें ताकि संकलक को सबसे कुशल कोड उत्पन्न करने की अनुमति मिल सके। मैं नहीं जानता कि कैसे जावा स्मृति का आयोजन करता है, लेकिन लगता है कि यह करने के लिए अलग नहीं है C/C++:

int a[10][100]; 
for (i = 0; i < 10; ++i) { 
    for (j = 0; j < 100; ++j) { 
     do_something_with(a[i][j]); 
    } 
} 
+2

क्या आप विस्तृत कर सकते हैं? –

+0

आप आमतौर पर नेस्टेड लूप में बहु-आयामी सरणी सामग्री को संसाधित करते हैं। इसलिए आपके सरणी को इस तरह व्यवस्थित किया जाना चाहिए कि आप अपने आंतरिक पाश में आसन्न तत्वों को संबोधित करें ताकि कन्पाइलर को सबसे कुशल कोड उत्पन्न करने की अनुमति मिल सके। मुझे नहीं पता कि जावा कैसे स्मृति का आयोजन करता है लेकिन लगता है कि यह सी/सी ++: int [10 [100]; (i = 0; i <10; ++ i) (j = 0; j <100; ++ j) do_soemething_with (a [i] [j]); – user1728219

3

जब हॉटस्पॉट पर यह कोशिश कर (सटीक आंकड़े उन आप Dalvik पर मिल से अलग हो सकता है, लेकिन निष्कर्ष होना चाहिए

वस्तु सरणी (1000x2x2): 76034 बाइट्स
वस्तु सरणी (2x2x1000): 16137 बाइट्स

यह एक किसी न किसी गणना के साथ कतार में है: समान), मैं निम्नलिखित परिणाम प्राप्त

[2][2][1000]      
Array #  Header Size Memory Number Total 
1    16  2  24  1  24 
2    16  2  24  2  48 
3    16 1000 4016  4 16,064 

         Grand Total  16,136 


[1000][2][2]      
Array #  Header Size Memory Number Total 
1    16 1000 4016  1 4,016 
2    16  2  24 1000 24,000 
3    16  2  24 2000 48,000 

         Grand Total  76,016 

टेस्ट नीचे कोड, -XX:-UseTLAB के साथ चलाने के अधिक सटीक परिणाम प्राप्त करने के लिए।

public class TestMemory { 

    private static final int SIZE = 100; 
    private static Runnable r; 
    private static Object o; 

    private static void test(Runnable r, String name, int numberOfObjects) { 
     long mem = Runtime.getRuntime().freeMemory(); 
     r.run(); 
     System.out.println(name + ": " + (mem - Runtime.getRuntime().freeMemory())/numberOfObjects + " bytes"); 
    } 

    public static void main(String[] args) throws Exception { 
     r = new Runnable() { public void run() { for (int i = 0; i < SIZE; i++) o = new Object[1000][2][2];} }; 
     test(r, "Object array (1000x2x2)", SIZE); 

     r = new Runnable() { public void run() { for (int i = 0; i < SIZE; i++) o = new Object[2][2][1000];} }; 
     test(r, "Object array (2x2x1000)", SIZE); 
    } 
} 
+1

क्या यह आश्चर्य की बात नहीं है कि यह अनुकूलित नहीं है? अंतर बहुत बड़ा है और बहुत से लोग इस बारे में अनजान हैं। [] आरोही क्रम में [] के बीच लिखे गए सॉर्टिंग नंबरों को करने योग्य होना चाहिए, है ना? –

+0

@AdamStelmaszczyk मुझे पता था कि यह अलग था लेकिन कभी अंतर की गणना नहीं की थी। यह वास्तव में बड़ा है। और मुझे कोई कारण नहीं दिखता कि इसे अनुकूलित क्यों नहीं किया जा सकता क्योंकि आप "पॉइंटर्स को स्थानांतरित नहीं कर सकते" इसलिए मुझे नहीं लगता कि इसका नकारात्मक प्रभाव क्या होगा ... – assylias

3

हां इससे कोई फर्क पड़ता है। बस -Xmx8M के साथ इस प्रयास करें:

// throws OutOfMemoryError 
public static void main(String[] args) { 
    int[][] a = new int[500000][2]; 
    System.out.println("a.length: '" + (a.length) + "'"); 
} 

// works 
public static void main(String[] args) { 
    int[][] a = new int[2][500000]; 
    System.out.println("a.length: '" + (a.length) + "'"); 
} 

पहले एक एक OutOfMemoryError फेंक देते हैं, एक दूसरे के पास होगा।

कारण यह है कि पहला संस्करण 500.000 सरणी लंबाई 2 बनाता है, जबकि दूसरा एक लंबाई 500.000 की 2 Arrays बनाता है।

Reference:

जैसे C एक भाषा में, एक दो आयामी सरणी (या वास्तव में किसी भी बहुआयामी सरणी) अनिवार्य रूप से विवेकपूर्ण सूचक हेरफेर के साथ एक आयामी सरणी है। जावा में यह मामला नहीं है, जहां एक बहुआयामी सरणी वास्तव में नेस्टेड सरणी का एक सेट है। इसका मतलब है कि एक द्वि-आयामी सरणी की प्रत्येक पंक्ति में किसी ऑब्जेक्ट का ओवरहेड होता है, क्योंकि यह वास्तव में एक अलग वस्तु है!

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