जावा में किसी वस्तु की मेमोरी खपत क्या है?


216

क्या मेमोरी स्पेस एक वस्तु द्वारा 100 विशेषताओं के साथ उपभोग किया जाता है, जो 100 वस्तुओं के समान है, एक विशेषता प्रत्येक के साथ है?

किसी वस्तु के लिए कितनी मेमोरी आवंटित की जाती है?
एक विशेषता जोड़ते समय कितना अतिरिक्त स्थान का उपयोग किया जाता है?

जवाबों:


180

माइंडप्रॉड बताता है कि यह जवाब देने के लिए एक सीधा सवाल नहीं है:

एक JVM किसी भी तरह से डेटा को स्टोर करने के लिए स्वतंत्र है, यह किसी भी तरह से पैडिंग या ओवरहेड के साथ आंतरिक, बड़े या छोटे एंडियन को प्रसन्न करता है, हालांकि आदिमों को ऐसा व्यवहार करना चाहिए जैसे कि उनका आधिकारिक आकार हो।
उदाहरण के लिए, JVM या देशी कंपाइलर boolean[]64-बिट लॉन्ग चंक्स जैसे a में स्टोर करने का निर्णय ले सकता है BitSet। यह आपको बताने की जरूरत नहीं है, इसलिए जब तक कार्यक्रम वही जवाब देता है।

  • यह स्टैक पर कुछ अस्थायी वस्तुओं को आवंटित कर सकता है।
  • यह कुछ चर या विधि कॉल को अस्तित्व से पूरी तरह से अनुकूलित कर सकता है जो उन्हें स्थिरांक के साथ बदल देता है।
  • यह तरीकों या छोरों का संस्करण हो सकता है, अर्थात एक विधि के दो संस्करणों को संकलित करें, प्रत्येक एक निश्चित स्थिति के लिए अनुकूलित, फिर सामने वाला तय करें कि किसे कॉल करना है।

फिर बेशक हार्डवेयर और OS में मल्टीलेयर कैश, चिप-कैश, SRAM कैश, DRAM कैश, साधारण रैम वर्किंग सेट और डिस्क पर बैकिंग स्टोर है। आपके डेटा को हर कैश स्तर पर डुप्लिकेट किया जा सकता है। यह सब जटिलता का मतलब है कि आप केवल रैम की खपत का अनुमान लगा सकते हैं।

माप के तरीके

आप Instrumentation.getObjectSize()किसी वस्तु द्वारा खपत भंडारण का अनुमान प्राप्त करने के लिए उपयोग कर सकते हैं ।

वास्तविक ऑब्जेक्ट लेआउट, पदचिह्न और संदर्भों की कल्पना करने के लिए , आप JOL (जावा ऑब्जेक्ट लेआउट) टूल का उपयोग कर सकते हैं ।

ऑब्जेक्ट हेडर और ऑब्जेक्ट संदर्भ

आधुनिक 64-बिट JDK में, एक ऑब्जेक्ट में 12-बाइट हेडर होता है, जिसे 8 बाइट्स के कई में रखा जाता है, इसलिए न्यूनतम ऑब्जेक्ट का आकार 16 बाइट्स होता है। 32-बिट JVM के लिए, ओवरहेड 8 बाइट्स है, जो 4 बाइट्स के कई में गद्देदार है। (से दिमित्री Spikhalskiy का जवाब , जायें का जवाब है, और जावावर्ल्ड ।)

आमतौर पर, संदर्भ 32 बिट प्लेटफॉर्म पर या 64 बिट प्लेटफॉर्म पर 4 बाइट हैं -Xmx32G; और 32Gb ( -Xmx32G) से ऊपर 8 बाइट्स । ( संकुचित ऑब्जेक्ट संदर्भ देखें )

परिणामस्वरूप, 64-बिट JVM को आमतौर पर 30-50% अधिक ढेर स्थान की आवश्यकता होती है। ( क्या मुझे 32- या 64-बिट JVM?, 2012, JDK 1.7 का उपयोग करना चाहिए )

बॉक्सिंग प्रकार, सरणियाँ, और तार

बॉक्सिंग रैपर में आदिम प्रकार ( जावावर्ल्ड से ) की तुलना में ओवरहेड होता है :

  • Integer: 16-बाइट का परिणाम मेरी उम्मीद से थोड़ा खराब है क्योंकि एक intमूल्य सिर्फ 4 अतिरिक्त बाइट्स में फिट हो सकता है। Integerजब मैं मूल्य को एक आदिम प्रकार के रूप में संग्रहीत कर सकता हूं, तो इसकी तुलना में मुझे 300 प्रतिशत मेमोरी ओवरहेड का उपयोग करना

  • Long: 16 बाइट्स भी: स्पष्ट रूप से, ढेर पर वास्तविक वस्तु का आकार एक विशेष सीपीयू प्रकार के लिए एक विशेष जेवीएम कार्यान्वयन द्वारा किए गए निम्न-स्तरीय मेमोरी संरेखण के अधीन है। ऐसा लगता है कि Longऑब्जेक्ट ओवरहेड के 8 बाइट्स हैं, वास्तविक वास्तविक मूल्य के लिए 8 बाइट्स अधिक हैं। इसके विपरीत, Integerएक अप्रयुक्त 4-बाइट छेद था, सबसे अधिक संभावना है क्योंकि जेवीएम I एक 8-बाइट शब्द सीमा पर बलों ऑब्जेक्ट संरेखण का उपयोग करता है।

अन्य कंटेनर महंगे भी हैं:

  • बहुआयामी सरणियाँ : यह एक और आश्चर्य प्रदान करता है।
    डेवलपर्स आमतौर पर int[dim1][dim2]संख्यात्मक और वैज्ञानिक कंप्यूटिंग जैसे निर्माण कार्य करते हैं ।

    एक int[dim1][dim2]सरणी उदाहरण में, प्रत्येक नेस्टेड int[dim2]सरणी Objectअपने आप में एक है। प्रत्येक सामान्य 16-बाइट सरणी ओवरहेड जोड़ता है। जब मुझे त्रिकोणीय या रैग्ड सरणी की आवश्यकता नहीं होती है, जो शुद्ध उपरि का प्रतिनिधित्व करता है। प्रभाव बढ़ता है जब सरणी आयाम बहुत भिन्न होते हैं।

    उदाहरण के लिए, एक int[128][2]उदाहरण 3,600 बाइट्स लेता है। 1,040 बाइट्स की तुलना में एक int[256]उदाहरण का उपयोग करता है (जिसमें समान क्षमता है), 3,600 बाइट्स 246 प्रतिशत ओवरहेड का प्रतिनिधित्व करते हैं। के चरम मामले में byte[256][1], ओवरहेड कारक लगभग 19 है! इसकी तुलना C / C ++ स्थिति से करें, जिसमें एक ही सिंटैक्स कोई संग्रहण ओवरहेड नहीं जोड़ता है।

  • String: एक Stringस्मृति विकास अपने आंतरिक चार सरणी के विकास को ट्रैक करता है। हालाँकि, Stringवर्ग ओवरहेड की एक और 24 बाइट्स जोड़ता है।

    String10 वर्ण या उससे कम आकार के एक गैर-रिक्त के लिए, उपयोगी पेलोड (लंबाई के लिए प्रत्येक चार प्लस 4 बाइट्स के लिए 2 बाइट्स) के सापेक्ष अतिरिक्त उपरि लागत 100 से 400 प्रतिशत तक होती है।

संरेखण

इस उदाहरण वस्तु पर विचार करें :

class X {                      // 8 bytes for reference to the class definition
   int a;                      // 4 bytes
   byte b;                     // 1 byte
   Integer c = new Integer();  // 4 bytes for a reference
}

एक भोली राशि बताती है कि एक उदाहरण X17 बाइट्स का उपयोग करेगा। हालांकि, संरेखण (जिसे पैडिंग भी कहा जाता है) के कारण, जेवीएम 8 बाइट्स के गुणकों में मेमोरी आवंटित करता है, इसलिए 17 बाइट्स के बजाय यह 24 बाइट्स आवंटित करेगा।


int [१२ int] [६]: ६ ints की १२ arr सरणियाँ - कुल में in६० ints, डेटा के ३० by२ बाइट्स + २०६४ बाइट्स ऑब्जेक्ट ओवरहेड = ५१६६ बाइट्स कुल। int [256]: 256 कुल में ints - इसलिए गैर-तुलनीय। int [768]: 3072 बाइट्स डेटा + 16 बाइट्स ओवरहेड - 2 डी सरणी के स्थान के बारे में 3/5 नॉट - काफी 246% ओवरहेड नहीं!
JeeBee

आह, मूल लेख में int [128] [2] int [128] [6] का उपयोग नहीं किया गया था - आश्चर्य है कि यह कैसे बदल गया। यह भी दर्शाता है कि चरम उदाहरण एक अलग कहानी बता सकते हैं।
JeeBee

2
64 बिट जेवीएम में ओवरहेड 16 बाइट्स है।
टिम कूपर

3
@AlexWien: कुछ कचरा-संग्रह योजनाएँ एक न्यूनतम वस्तु का आकार ले सकती हैं जो पैडिंग से अलग है। कचरा संग्रह के दौरान, एक बार किसी वस्तु को पुराने स्थान से एक नए में कॉपी कर लिया जाता है, पुराने स्थान को ऑब्जेक्ट के लिए डेटा को और अधिक रखने की आवश्यकता नहीं हो सकती है, लेकिन इसे नए स्थान के संदर्भ में रखने की आवश्यकता होगी; इसमें ऑब्जेक्ट के पुराने स्थान पर एक संदर्भ को संग्रहीत करने की आवश्यकता हो सकती है जिसमें पहला संदर्भ खोजा गया था और पुरानी वस्तु के भीतर उस संदर्भ की ऑफसेट [चूंकि पुरानी वस्तु में अभी भी संदर्भ हो सकते हैं जो अभी तक संसाधित नहीं हुए हैं]।
सुपरकैट

2
@AlexWien: कचरा-कलेक्टर की पुस्तक-रखने की जानकारी रखने के लिए किसी ऑब्जेक्ट के पुराने स्थान पर मेमोरी का उपयोग करने से उस उद्देश्य के लिए अन्य मेमोरी को आवंटित करने की आवश्यकता से बचा जाता है, लेकिन एक न्यूनतम ऑब्जेक्ट आकार को लागू कर सकता है जो अन्यथा अन्यथा आवश्यक होगा। मुझे लगता है कि .NET कचरा कलेक्टर का कम से कम एक संस्करण उस दृष्टिकोण का उपयोग करता है; कुछ जावा कचरा संग्रहकर्ताओं के लिए भी ऐसा करना निश्चित रूप से संभव होगा।
सुपरकाट

34

यह वास्तुकला / jdk पर निर्भर करता है। एक आधुनिक JDK और 64 बिट आर्किटेक्चर के लिए, एक ऑब्जेक्ट में 12-बाइट्स हेडर और 8 बाइट्स से पैडिंग है - इसलिए न्यूनतम ऑब्जेक्ट का आकार 16 बाइट्स है। आप आकार निर्धारित करने के लिए जावा ऑब्जेक्ट लेआउट नामक उपकरण का उपयोग कर सकते हैं और ऑब्जेक्ट लेआउट और किसी भी इकाई की आंतरिक संरचना के बारे में विवरण प्राप्त कर सकते हैं या वर्ग संदर्भ द्वारा इस जानकारी का अनुमान लगा सकते हैं। मेरे पर्यावरण पर पूर्णांक के लिए आउटपुट का उदाहरण:

Running 64-bit HotSpot VM.
Using compressed oop with 3-bit shift.
Using compressed klass with 3-bit shift.
Objects are 8 bytes aligned.
Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]

java.lang.Integer object internals:
 OFFSET  SIZE  TYPE DESCRIPTION                    VALUE
      0    12       (object header)                N/A
     12     4   int Integer.value                  N/A
Instance size: 16 bytes (estimated, the sample instance is not available)
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

इसलिए, इंटेगर के लिए, उदाहरण का आकार 16 बाइट्स है, क्योंकि हेडर के ठीक बाद और बाउंड्री पैडिंग से पहले 4-बाइट्स को कॉम्पैक्ट किया गया है।

कोड नमूना:

import org.openjdk.jol.info.ClassLayout;
import org.openjdk.jol.util.VMSupport;

public static void main(String[] args) {
    System.out.println(VMSupport.vmDetails());
    System.out.println(ClassLayout.parseClass(Integer.class).toPrintable());
}

यदि आप JOL पाने के लिए मावेन का उपयोग करते हैं:

<dependency>
    <groupId>org.openjdk.jol</groupId>
    <artifactId>jol-core</artifactId>
    <version>0.3.2</version>
</dependency>

28

प्रत्येक ऑब्जेक्ट के पास अपने संबंधित मॉनिटर और प्रकार की जानकारी के लिए एक निश्चित ओवरहेड है, साथ ही साथ स्वयं फ़ील्ड्स भी। इसके अलावा, खेतों को बहुत बाहर रखा जा सकता है, हालांकि जेवीएम फिट बैठता है (मुझे विश्वास है) - लेकिन जैसा कि एक अन्य जवाब में दिखाया गया है , कम से कम कुछ जेवीएम काफी कसकर पैक करेंगे। इस तरह एक वर्ग पर विचार करें:

public class SingleByte
{
    private byte b;
}

बनाम

public class OneHundredBytes
{
    private byte b00, b01, ..., b99;
}

32-बिट JVM पर, मैं अपेक्षा करता हूं कि SingleByte1200 बाइट्स (ओवरहेड + 8 बाइट्स के 8 बाइट्स को पैडिंग / अलाइनमेंट के कारण क्षेत्र के लिए) लेने के 100 उदाहरण मिलेंगे। मैं एक उदाहरण के OneHundredBytesलिए 108 बाइट्स लेना चाहता हूँ - ओवरहेड, और फिर 100 बाइट्स, पैक्ड। यह निश्चित रूप से जेवीएम द्वारा भिन्न हो सकता है - एक कार्यान्वयन में खेतों को पैक नहीं करने का निर्णय लिया जा सकता है OneHundredBytes, जिसके कारण यह 408 बाइट्स (= 8 बाइट्स ओवरहेड + 4 * 100 संरेखित / गद्देदार बाइट्स) ले सकता है। 64 बिट JVM पर ओवरहेड अच्छी तरह से बड़ा हो सकता है (निश्चित नहीं)।

संपादित करें: नीचे टिप्पणी देखें; जाहिरा तौर पर हॉटस्पॉट पैड को 32 के बजाय 8 बाइट की सीमा तक, इसलिए प्रत्येक उदाहरण में SingleByte16 बाइट्स होंगे।

किसी भी तरह से, "एकल बड़ी वस्तु" कम से कम कई छोटी वस्तुओं की तरह कुशल होगी - इस तरह के सरल मामलों के लिए।


9
वास्तव में, सिंगलबाइट का एक उदाहरण सन जेवीएम पर 16 बाइट्स लेगा, जो कि 8 बाइट्स ओवरहेड, मैदान के लिए 4 बाइट्स, और फिर ऑब्जेक्ट पैडिंग के लिए 4 बाइट्स है, क्योंकि हॉटस्पॉट कंपाइलर राउंड्स 8. के ​​गुणक के लिए सब कुछ गोल करता है।
पॉल वैग्लैंड

6

किसी प्रोग्राम की कुल इस्तेमाल की गई / फ्री मेमोरी को प्रोग्राम में प्राप्त किया जा सकता है

java.lang.Runtime.getRuntime();

रनटाइम में कई विधि होती है जो मेमोरी से संबंधित होती है। निम्न कोडिंग उदाहरण इसके उपयोग को प्रदर्शित करता है।

package test;

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

 public class PerformanceTest {
     private static final long MEGABYTE = 1024L * 1024L;

     public static long bytesToMegabytes(long bytes) {
         return bytes / MEGABYTE;
     }

     public static void main(String[] args) {
         // I assume you will know how to create a object Person yourself...
         List < Person > list = new ArrayList < Person > ();
         for (int i = 0; i <= 100000; i++) {
             list.add(new Person("Jim", "Knopf"));
         }
         // Get the Java runtime
         Runtime runtime = Runtime.getRuntime();
         // Run the garbage collector
         runtime.gc();
         // Calculate the used memory
         long memory = runtime.totalMemory() - runtime.freeMemory();
         System.out.println("Used memory is bytes: " + memory);
         System.out.println("Used memory is megabytes: " + bytesToMegabytes(memory));
     }
 }

6

ऐसा प्रतीत होता है कि प्रत्येक ऑब्जेक्ट में 32-बिट सिस्टम पर 16 बाइट्स का ओवरहेड (और 64-बिट सिस्टम पर 24-बाइट) है।

http://algs4.cs.princeton.edu/14analysis/ जानकारी का एक अच्छा स्रोत है। कई अच्छे लोगों के बीच एक उदाहरण निम्नलिखित है।

यहां छवि विवरण दर्ज करें

http://www.cs.virginia.edu/kim/publicity/pldi09tutorials/memory-efficient-java-tutorial.pdf भी बहुत जानकारीपूर्ण है, उदाहरण के लिए:

यहां छवि विवरण दर्ज करें


"ऐसा प्रतीत होता है कि प्रत्येक वस्तु में 32-बिट सिस्टम पर 16 बाइट्स का ओवरहेड (और 64-बिट पर 24-बाइट) है।" यह सही नहीं है, कम से कम वर्तमान जेडीके के लिए। इंटेगर उदाहरण के लिए मेरे जवाब पर एक नज़र डालें । 64-बिट सिस्टम और आधुनिक JDK के लिए हेडर के लिए ऑब्जेक्ट का ओवरहेड कम से कम 12 बाइट्स है। पैडिंग के कारण अधिक हो सकता है, ऑब्जेक्ट में फ़ील्ड्स के वास्तविक लेआउट पर निर्भर करता है।
दिमित्री स्पिकाल्स्की

स्मृति कुशल जावा ट्यूटोरियल की दूसरी कड़ी मृत प्रतीत होती है - मुझे "निषिद्ध" मिलता है।
tsleyson

6

क्या मेमोरी स्पेस एक वस्तु द्वारा 100 विशेषताओं के साथ उपभोग किया जाता है, जो 100 वस्तुओं के समान है, एक विशेषता प्रत्येक के साथ है?

नहीं।

किसी वस्तु के लिए कितनी मेमोरी आवंटित की जाती है?

  • ओवरहेड 32-बिट पर 8 बाइट्स, 64-बिट पर 12 बाइट्स है; और फिर 4 बाइट्स (32-बिट) या 8 बाइट्स (64-बिट) के कई तक गोल किया गया।

एक विशेषता जोड़ते समय कितना अतिरिक्त स्थान का उपयोग किया जाता है?

  • गुण 1 बाइट (बाइट) से 8 बाइट (लंबे / डबल) तक होती है, लेकिन संदर्भ या तो 4 बाइट या 8 बाइट्स निर्भर करता है नहीं पर कि क्या यह के 32bit या 64bit, बल्कि चाहे -Xmx है <32GB या> = 32Gb: ठेठ 64 -बिट JVM का एक अनुकूलन है, जिसे "-UseCompressedOops" कहा जाता है, जो कि ढेर को 32Gb से कम होने पर 4 बाइट्स के संदर्भ में संपीड़ित करता है।

1
एक चर 16bit है, 8bit नहीं।
कोमोनड

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

5

नहीं, किसी ऑब्जेक्ट को रजिस्टर करने में थोड़ी मेमोरी भी लगती है। 1 विशेषता वाले 100 ऑब्जेक्ट अधिक मेमोरी लेंगे।


4

प्रश्न बहुत व्यापक होगा।

यह वर्ग चर पर निर्भर करता है या आप जावा में मेमोरी उपयोग के रूप में कह सकते हैं।

इसमें हेडर और रेफरेंस के लिए कुछ अतिरिक्त मेमोरी की आवश्यकता होती है।

जावा ऑब्जेक्ट द्वारा उपयोग की गई ढेर मेमोरी में शामिल हैं

  • आदिम क्षेत्रों के लिए स्मृति, उनके आकार के अनुसार (आदिम प्रकार के आकार के लिए नीचे देखें);

  • संदर्भ फ़ील्ड के लिए मेमोरी (प्रत्येक 4 बाइट्स);

  • ऑब्जेक्ट हेडर, जिसमें "हाउसकीपिंग" जानकारी के कुछ बाइट्स शामिल हैं;

जावा में वस्तुओं को कुछ "हाउसकीपिंग" जानकारी की भी आवश्यकता होती है, जैसे कि किसी वस्तु की कक्षा, आईडी और स्थिति के झंडे को रिकॉर्ड करना जैसे कि वस्तु वर्तमान में उपलब्ध है, वर्तमान में सिंक्रनाइज़ेशन-लॉक आदि।

जावा ऑब्जेक्ट हेडर का आकार 32 और 64 बिट जेवीएम पर भिन्न होता है।

यद्यपि ये मुख्य मेमोरी उपभोक्ता हैं jvm को अतिरिक्त फ़ील्ड की भी आवश्यकता होती है जैसे कभी-कभी कोड आदि के संरेखण के लिए

आदिम प्रकार के आकार

बूलियन और बाइट - 1

चार और छोटा - 2

int & float - 4

लंबा और दोहरा - 8


पाठकों को भी यह पत्र बहुत रोशन लग सकता है: cs.virginia.edu/kim/publicity/pldi09tutorials/…
quellish

3

मैं java.lang.instrument.Instrumentation दृष्टिकोण से एक और उत्तर में उल्लिखित बहुत अच्छे परिणाम प्राप्त कर चुका हूं । इसके उपयोग के अच्छे उदाहरणों के लिए, देखें प्रवेश, इंस्ट्रूमेंटेशन मेमोरी काउंटर से जावास्पेशलिस्ट्स न्यूज़लैटर और सोर्सफ़ॉर्ग पर java.sizeOf लाइब्रेरी।


2

यदि यह किसी के लिए उपयोगी है, तो आप किसी ऑब्जेक्ट के मेमोरी उपयोग की क्वेरी के लिए मेरी वेब साइट से एक छोटा जावा एजेंट डाउनलोड कर सकते हैं । यह आपको "गहरी" मेमोरी उपयोग के रूप में अच्छी तरह से क्वेरी करने देगा।


यह एक अनुमान लगाने के लिए बहुत अच्छा काम किया कि (String, Integer)प्रति अमरूद, अमरूद कैश कितनी मेमोरी का उपयोग करता है। धन्यवाद!
स्टीव के

1

नहीं, 100 छोटी वस्तुओं को एक बड़ी की तुलना में अधिक जानकारी (मेमोरी) की आवश्यकता होती है।


0

मेमोरी कितनी खपत होती है, इस बारे में नियम जेवीएम कार्यान्वयन और सीपीयू आर्किटेक्चर (उदाहरण के लिए 32 बिट बनाम 64 बिट) पर निर्भर करते हैं।

SUN JVM के लिए विस्तृत नियमों के लिए मेरा पुराना ब्लॉग देखें

सादर, मार्कस


मुझे पूरा यकीन है कि सन जावा 1.6 64 बिट, एक सादे वस्तु के लिए 12 बाइट्स की आवश्यकता है + 4 पैडिंग = 16; ऑब्जेक्ट + एक पूर्णांक फ़ील्ड = 12 + 4 = 16
एलेक्स जूल

क्या आपने अपना ब्लॉग बंद कर दिया?
जोहान बोले

वास्तव में नहीं, यकीन नहीं है कि एसएपी ब्लॉग किसी तरह चले गए। इसमें से अधिकांश यहाँ पाया जा सकता है kohlerm.blogspot.com
kohlerm
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.