जवाबों:
माइंडप्रॉड बताता है कि यह जवाब देने के लिए एक सीधा सवाल नहीं है:
एक 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 बाइट्स जोड़ता है।
String
10 वर्ण या उससे कम आकार के एक गैर-रिक्त के लिए, उपयोगी पेलोड (लंबाई के लिए प्रत्येक चार प्लस 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
}
एक भोली राशि बताती है कि एक उदाहरण X
17 बाइट्स का उपयोग करेगा। हालांकि, संरेखण (जिसे पैडिंग भी कहा जाता है) के कारण, जेवीएम 8 बाइट्स के गुणकों में मेमोरी आवंटित करता है, इसलिए 17 बाइट्स के बजाय यह 24 बाइट्स आवंटित करेगा।
यह वास्तुकला / 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>
प्रत्येक ऑब्जेक्ट के पास अपने संबंधित मॉनिटर और प्रकार की जानकारी के लिए एक निश्चित ओवरहेड है, साथ ही साथ स्वयं फ़ील्ड्स भी। इसके अलावा, खेतों को बहुत बाहर रखा जा सकता है, हालांकि जेवीएम फिट बैठता है (मुझे विश्वास है) - लेकिन जैसा कि एक अन्य जवाब में दिखाया गया है , कम से कम कुछ जेवीएम काफी कसकर पैक करेंगे। इस तरह एक वर्ग पर विचार करें:
public class SingleByte
{
private byte b;
}
बनाम
public class OneHundredBytes
{
private byte b00, b01, ..., b99;
}
32-बिट JVM पर, मैं अपेक्षा करता हूं कि SingleByte
1200 बाइट्स (ओवरहेड + 8 बाइट्स के 8 बाइट्स को पैडिंग / अलाइनमेंट के कारण क्षेत्र के लिए) लेने के 100 उदाहरण मिलेंगे। मैं एक उदाहरण के OneHundredBytes
लिए 108 बाइट्स लेना चाहता हूँ - ओवरहेड, और फिर 100 बाइट्स, पैक्ड। यह निश्चित रूप से जेवीएम द्वारा भिन्न हो सकता है - एक कार्यान्वयन में खेतों को पैक नहीं करने का निर्णय लिया जा सकता है OneHundredBytes
, जिसके कारण यह 408 बाइट्स (= 8 बाइट्स ओवरहेड + 4 * 100 संरेखित / गद्देदार बाइट्स) ले सकता है। 64 बिट JVM पर ओवरहेड अच्छी तरह से बड़ा हो सकता है (निश्चित नहीं)।
संपादित करें: नीचे टिप्पणी देखें; जाहिरा तौर पर हॉटस्पॉट पैड को 32 के बजाय 8 बाइट की सीमा तक, इसलिए प्रत्येक उदाहरण में SingleByte
16 बाइट्स होंगे।
किसी भी तरह से, "एकल बड़ी वस्तु" कम से कम कई छोटी वस्तुओं की तरह कुशल होगी - इस तरह के सरल मामलों के लिए।
किसी प्रोग्राम की कुल इस्तेमाल की गई / फ्री मेमोरी को प्रोग्राम में प्राप्त किया जा सकता है
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));
}
}
ऐसा प्रतीत होता है कि प्रत्येक ऑब्जेक्ट में 32-बिट सिस्टम पर 16 बाइट्स का ओवरहेड (और 64-बिट सिस्टम पर 24-बाइट) है।
http://algs4.cs.princeton.edu/14analysis/ जानकारी का एक अच्छा स्रोत है। कई अच्छे लोगों के बीच एक उदाहरण निम्नलिखित है।
http://www.cs.virginia.edu/kim/publicity/pldi09tutorials/memory-efficient-java-tutorial.pdf भी बहुत जानकारीपूर्ण है, उदाहरण के लिए:
क्या मेमोरी स्पेस एक वस्तु द्वारा 100 विशेषताओं के साथ उपभोग किया जाता है, जो 100 वस्तुओं के समान है, एक विशेषता प्रत्येक के साथ है?
नहीं।
किसी वस्तु के लिए कितनी मेमोरी आवंटित की जाती है?
एक विशेषता जोड़ते समय कितना अतिरिक्त स्थान का उपयोग किया जाता है?
प्रश्न बहुत व्यापक होगा।
यह वर्ग चर पर निर्भर करता है या आप जावा में मेमोरी उपयोग के रूप में कह सकते हैं।
इसमें हेडर और रेफरेंस के लिए कुछ अतिरिक्त मेमोरी की आवश्यकता होती है।
जावा ऑब्जेक्ट द्वारा उपयोग की गई ढेर मेमोरी में शामिल हैं
आदिम क्षेत्रों के लिए स्मृति, उनके आकार के अनुसार (आदिम प्रकार के आकार के लिए नीचे देखें);
संदर्भ फ़ील्ड के लिए मेमोरी (प्रत्येक 4 बाइट्स);
ऑब्जेक्ट हेडर, जिसमें "हाउसकीपिंग" जानकारी के कुछ बाइट्स शामिल हैं;
जावा में वस्तुओं को कुछ "हाउसकीपिंग" जानकारी की भी आवश्यकता होती है, जैसे कि किसी वस्तु की कक्षा, आईडी और स्थिति के झंडे को रिकॉर्ड करना जैसे कि वस्तु वर्तमान में उपलब्ध है, वर्तमान में सिंक्रनाइज़ेशन-लॉक आदि।
जावा ऑब्जेक्ट हेडर का आकार 32 और 64 बिट जेवीएम पर भिन्न होता है।
यद्यपि ये मुख्य मेमोरी उपभोक्ता हैं jvm को अतिरिक्त फ़ील्ड की भी आवश्यकता होती है जैसे कभी-कभी कोड आदि के संरेखण के लिए
आदिम प्रकार के आकार
बूलियन और बाइट - 1
चार और छोटा - 2
int & float - 4
लंबा और दोहरा - 8
मैं java.lang.instrument.Instrumentation दृष्टिकोण से एक और उत्तर में उल्लिखित बहुत अच्छे परिणाम प्राप्त कर चुका हूं । इसके उपयोग के अच्छे उदाहरणों के लिए, देखें प्रवेश, इंस्ट्रूमेंटेशन मेमोरी काउंटर से जावास्पेशलिस्ट्स न्यूज़लैटर और सोर्सफ़ॉर्ग पर java.sizeOf लाइब्रेरी।
यदि यह किसी के लिए उपयोगी है, तो आप किसी ऑब्जेक्ट के मेमोरी उपयोग की क्वेरी के लिए मेरी वेब साइट से एक छोटा जावा एजेंट डाउनलोड कर सकते हैं । यह आपको "गहरी" मेमोरी उपयोग के रूप में अच्छी तरह से क्वेरी करने देगा।
(String, Integer)
प्रति अमरूद, अमरूद कैश कितनी मेमोरी का उपयोग करता है। धन्यवाद!
मेमोरी कितनी खपत होती है, इस बारे में नियम जेवीएम कार्यान्वयन और सीपीयू आर्किटेक्चर (उदाहरण के लिए 32 बिट बनाम 64 बिट) पर निर्भर करते हैं।
SUN JVM के लिए विस्तृत नियमों के लिए मेरा पुराना ब्लॉग देखें
सादर, मार्कस