जावा में, किसी वस्तु के आकार को निर्धारित करने का सबसे अच्छा तरीका क्या है?


616

मेरे पास एक एप्लिकेशन है जो डेटा पंक्तियों के ढेर के साथ एक सीएसवी फ़ाइल पढ़ता है। मैं उपयोगकर्ता को डेटा के प्रकारों के आधार पर पंक्तियों की संख्या का सारांश देता हूं, लेकिन मैं यह सुनिश्चित करना चाहता हूं कि मैं डेटा की बहुत सी पंक्तियों में नहीं पढ़ता हूं और OutOfMemoryErrorएस। प्रत्येक पंक्ति एक वस्तु में तब्दील हो जाती है। क्या उस वस्तु का आकार प्रोग्रामेटिक रूप से ज्ञात करने का एक आसान तरीका है? क्या एक संदर्भ है जो परिभाषित करता है कि बड़े आदिम प्रकार और वस्तु संदर्भ एक के लिए कैसे हैं VM?

अभी, मेरे पास कोड है जो 32,000 पंक्तियों तक पढ़ता है , लेकिन मैं उस कोड को भी पसंद करूंगा जो कहता है कि जब तक मैंने 32MB मेमोरी का उपयोग नहीं किया है, तब तक कई पंक्तियों को पढ़ें । शायद यह एक अलग सवाल है, लेकिन मैं अभी भी जानना चाहूंगा।


मैंने अपने एजेंट को mvan configs के साथ जोड़ा और बताया कि यहाँ कैसे: stackoverflow.com/a/36102269/711855
juanmf

जवाबों:


461

आप java.lang.instrument पैकेज का उपयोग कर सकते हैं

संकलित करें और इस कक्षा को JAR में रखें:

import java.lang.instrument.Instrumentation;

public class ObjectSizeFetcher {
    private static Instrumentation instrumentation;

    public static void premain(String args, Instrumentation inst) {
        instrumentation = inst;
    }

    public static long getObjectSize(Object o) {
        return instrumentation.getObjectSize(o);
    }
}

निम्नलिखित को अपने में जोड़ें MANIFEST.MF:

Premain-Class: ObjectSizeFetcher

GetObjectSize का उपयोग करें:

public class C {
    private int x;
    private int y;

    public static void main(String [] args) {
        System.out.println(ObjectSizeFetcher.getObjectSize(new C()));
    }
}

के साथ आमंत्रित करें:

java -javaagent:ObjectSizeFetcherAgent.jar C

2
@Stefan अच्छा संकेत! आप कृपया बता सकते हैं, के आकार होगा क्या byte[0], byte[1], byte[5], int[0], int[1], int[2]दृष्टिकोण का उपयोग कर आप वर्णित? यह अच्छा होगा, यदि परिणाम में सरणी और मेमोरी संरेखण की लंबाई के लिए ओवरहेड शामिल है।
dma_k

8
मैंने यह कोशिश की और अजीब और अनपेक्षित परिणाम मिले। आकार की परवाह किए बिना स्ट्रिंग्स हमेशा 32 थे। मैंने सोचा था कि यह पॉइंटर का आकार था, लेकिन एक और अपरिवर्तनीय वर्ग के लिए, जिसे मैंने बनाया, मुझे 24 मिला। यह आदिम के लिए अच्छी तरह से काम करता है, लेकिन फिर आपको वास्तव में एक कार्यक्रम की आवश्यकता नहीं है जो आपको बता सके कि कितना बड़ा है।
ब्रेल

6
@ यह समाधान केवल एक "निर्दिष्ट वस्तु द्वारा खपत भंडारण की मात्रा का अनुमान" है, जैसा कि प्रलेखन में निर्दिष्ट है। इसके अलावा, मुझे लगता है कि लेखकों ने स्ट्रिंग के आकार को 32 बाइट्स (केवल पॉइंटर?) के रूप में सेट करने का निर्णय लिया, क्योंकि जावा के स्ट्रिंग पूल के कारण, यह कहना मुश्किल है कि क्या स्ट्रिंग का उदाहरण साझा किया गया है (पूल में संग्रहीत) या स्थानीय और एक वर्ग के लिए अद्वितीय।
आंद्रेई I

11
जार को निर्यात न करने पर मैं उपयोगकर्ता को कैसे ऑब्जेक्ट कर सकता हूं? मेरे पास ग्रहण में परीक्षण जावा परियोजना है।
यूरा शिनकरेव

3
@brel वास्तविक लंबाई की परवाह किए बिना एक स्ट्रिंग केवल 32 बाइट्स है, क्योंकि एक स्ट्रिंग की चर लंबाई का हिस्सा एक चार [] में संग्रहीत किया जाता है, जो कि यह स्वयं का ऑब्जेक्ट है। किसी वस्तु का सही आकार प्राप्त करने के लिए, आपको स्वयं के आकार और प्रत्येक वस्तु के आकार को जोड़ने की आवश्यकता है।
tombrown52

116

आपको JOL का उपयोग करना चाहिए , OpenJDK परियोजना के भाग के रूप में विकसित एक उपकरण।

JVMs में ऑब्जेक्ट लेआउट योजनाओं का विश्लेषण करने के लिए JOL (जावा ऑब्जेक्ट लेआउट) छोटा टूलबॉक्स है। ये उपकरण वास्तविक वस्तु लेआउट, पदचिह्न और संदर्भों को डिकोड करने के लिए अनसेफ, जेवीएमटीआई, और सर्विसेबिलिटी एजेंट (एसए) का भारी उपयोग कर रहे हैं। यह JOL हीप डंप, विनिर्देश मान्यताओं आदि पर निर्भर अन्य साधनों की तुलना में अधिक सटीक बनाता है।

आदिम, संदर्भ और सरणी तत्वों के आकार प्राप्त करने के लिए, उपयोग करें VMSupport.vmDetails()। ओरेकल JDK 1.8.0_40 पर 64-बिट विंडोज (सभी निम्नलिखित उदाहरणों के लिए प्रयुक्त) पर चल रहा है, यह विधि वापस आती है

Running 64-bit HotSpot VM.
Using compressed oop with 0-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]

आप एक वस्तु उदाहरण के उथले आकार का उपयोग करके प्राप्त कर सकते हैं ClassLayout.parseClass(Foo.class).toPrintable()(वैकल्पिक रूप से एक उदाहरण के लिए toPrintable)। यह केवल उस वर्ग के एकल उदाहरण द्वारा खपत स्थान है; इसमें उस वर्ग द्वारा संदर्भित कोई अन्य ऑब्जेक्ट शामिल नहीं है। यह करता वस्तु हेडर के लिए वीएम भूमि के ऊपर, क्षेत्र संरेखण और गद्दी शामिल हैं। के लिए java.util.regex.Pattern:

java.util.regex.Pattern object internals:
 OFFSET  SIZE        TYPE DESCRIPTION                    VALUE
      0     4             (object header)                01 00 00 00 (0000 0001 0000 0000 0000 0000 0000 0000)
      4     4             (object header)                00 00 00 00 (0000 0000 0000 0000 0000 0000 0000 0000)
      8     4             (object header)                cb cf 00 20 (1100 1011 1100 1111 0000 0000 0010 0000)
     12     4         int Pattern.flags                  0
     16     4         int Pattern.capturingGroupCount    1
     20     4         int Pattern.localCount             0
     24     4         int Pattern.cursor                 48
     28     4         int Pattern.patternLength          0
     32     1     boolean Pattern.compiled               true
     33     1     boolean Pattern.hasSupplementary       false
     34     2             (alignment/padding gap)        N/A
     36     4      String Pattern.pattern                (object)
     40     4      String Pattern.normalizedPattern      (object)
     44     4        Node Pattern.root                   (object)
     48     4        Node Pattern.matchRoot              (object)
     52     4       int[] Pattern.buffer                 null
     56     4         Map Pattern.namedGroups            null
     60     4 GroupHead[] Pattern.groupNodes             null
     64     4       int[] Pattern.temp                   null
     68     4             (loss due to the next object alignment)
Instance size: 72 bytes (reported by Instrumentation API)
Space losses: 2 bytes internal + 4 bytes external = 6 bytes total

आप किसी वस्तु उदाहरण के गहरे आकार का उपयोग करके सारांश दृश्य प्राप्त कर सकते हैं GraphLayout.parseInstance(obj).toFootprint()। बेशक, पदचिह्न में कुछ वस्तुओं को साझा किया जा सकता है (अन्य वस्तुओं से भी संदर्भित), इसलिए यह उस स्थान का अतिव्यापीकरण है जिसे उस वस्तु के एकत्र होने पर पुनः प्राप्त किया जा सकता है। के परिणाम के लिए Pattern.compile("^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+$")( इस उत्तर से लिया गया ), जोल ने 1840 बाइट्स के कुल पदचिह्न की रिपोर्ट की, जिनमें से केवल 72 ही उदाहरण हैं।

java.util.regex.Pattern instance footprint:
     COUNT       AVG       SUM   DESCRIPTION
         1       112       112   [C
         3       272       816   [Z
         1        24        24   java.lang.String
         1        72        72   java.util.regex.Pattern
         9        24       216   java.util.regex.Pattern$1
        13        24       312   java.util.regex.Pattern$5
         1        16        16   java.util.regex.Pattern$Begin
         3        24        72   java.util.regex.Pattern$BitClass
         3        32        96   java.util.regex.Pattern$Curly
         1        24        24   java.util.regex.Pattern$Dollar
         1        16        16   java.util.regex.Pattern$LastNode
         1        16        16   java.util.regex.Pattern$Node
         2        24        48   java.util.regex.Pattern$Single
        40                1840   (total)

यदि आप इसके बजाय उपयोग करते हैं GraphLayout.parseInstance(obj).toPrintable(), तो jol आपको प्रत्येक संदर्भित वस्तु के क्षेत्र के संदर्भों का पता, आकार, प्रकार, मूल्य और पथ बताएगा, हालांकि यह आमतौर पर उपयोगी होने के लिए बहुत अधिक विवरण है। चल रहे पैटर्न उदाहरण के लिए, आपको निम्नलिखित मिल सकता है। (पते की संभावना रन के बीच बदल जाएगी।)

java.util.regex.Pattern object externals:
          ADDRESS       SIZE TYPE                             PATH                           VALUE
         d5e5f290         16 java.util.regex.Pattern$Node     .root.next.atom.next           (object)
         d5e5f2a0        120 (something else)                 (somewhere else)               (something else)
         d5e5f318         16 java.util.regex.Pattern$LastNode .root.next.next.next.next.next.next.next (object)
         d5e5f328      21664 (something else)                 (somewhere else)               (something else)
         d5e647c8         24 java.lang.String                 .pattern                       (object)
         d5e647e0        112 [C                               .pattern.value                 [^, [, a, -, z, A, -, Z, 0, -, 9, _, ., +, -, ], +, @, [, a, -, z, A, -, Z, 0, -, 9, -, ], +, \, ., [, a, -, z, A, -, Z, 0, -, 9, -, ., ], +, $]
         d5e64850        448 (something else)                 (somewhere else)               (something else)
         d5e64a10         72 java.util.regex.Pattern                                         (object)
         d5e64a58        416 (something else)                 (somewhere else)               (something else)
         d5e64bf8         16 java.util.regex.Pattern$Begin    .root                          (object)
         d5e64c08         24 java.util.regex.Pattern$BitClass .root.next.atom.val$rhs        (object)
         d5e64c20        272 [Z                               .root.next.atom.val$rhs.bits   [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, true, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false]
         d5e64d30         24 java.util.regex.Pattern$1        .root.next.atom.val$lhs.val$lhs.val$lhs.val$lhs.val$lhs.val$lhs (object)
         d5e64d48         24 java.util.regex.Pattern$1        .root.next.atom.val$lhs.val$lhs.val$lhs.val$lhs.val$lhs.val$rhs (object)
         d5e64d60         24 java.util.regex.Pattern$5        .root.next.atom.val$lhs.val$lhs.val$lhs.val$lhs.val$lhs (object)
         d5e64d78         24 java.util.regex.Pattern$1        .root.next.atom.val$lhs.val$lhs.val$lhs.val$lhs.val$rhs (object)
         d5e64d90         24 java.util.regex.Pattern$5        .root.next.atom.val$lhs.val$lhs.val$lhs.val$lhs (object)
         d5e64da8         24 java.util.regex.Pattern$5        .root.next.atom.val$lhs.val$lhs.val$lhs (object)
         d5e64dc0         24 java.util.regex.Pattern$5        .root.next.atom.val$lhs.val$lhs (object)
         d5e64dd8         24 java.util.regex.Pattern$5        .root.next.atom.val$lhs        (object)
         d5e64df0         24 java.util.regex.Pattern$5        .root.next.atom                (object)
         d5e64e08         32 java.util.regex.Pattern$Curly    .root.next                     (object)
         d5e64e28         24 java.util.regex.Pattern$Single   .root.next.next                (object)
         d5e64e40         24 java.util.regex.Pattern$BitClass .root.next.next.next.atom.val$rhs (object)
         d5e64e58        272 [Z                               .root.next.next.next.atom.val$rhs.bits [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false]
         d5e64f68         24 java.util.regex.Pattern$1        .root.next.next.next.atom.val$lhs.val$lhs.val$lhs (object)
         d5e64f80         24 java.util.regex.Pattern$1        .root.next.next.next.atom.val$lhs.val$lhs.val$rhs (object)
         d5e64f98         24 java.util.regex.Pattern$5        .root.next.next.next.atom.val$lhs.val$lhs (object)
         d5e64fb0         24 java.util.regex.Pattern$1        .root.next.next.next.atom.val$lhs.val$rhs (object)
         d5e64fc8         24 java.util.regex.Pattern$5        .root.next.next.next.atom.val$lhs (object)
         d5e64fe0         24 java.util.regex.Pattern$5        .root.next.next.next.atom      (object)
         d5e64ff8         32 java.util.regex.Pattern$Curly    .root.next.next.next           (object)
         d5e65018         24 java.util.regex.Pattern$Single   .root.next.next.next.next      (object)
         d5e65030         24 java.util.regex.Pattern$BitClass .root.next.next.next.next.next.atom.val$rhs (object)
         d5e65048        272 [Z                               .root.next.next.next.next.next.atom.val$rhs.bits [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false]
         d5e65158         24 java.util.regex.Pattern$1        .root.next.next.next.next.next.atom.val$lhs.val$lhs.val$lhs.val$lhs (object)
         d5e65170         24 java.util.regex.Pattern$1        .root.next.next.next.next.next.atom.val$lhs.val$lhs.val$lhs.val$rhs (object)
         d5e65188         24 java.util.regex.Pattern$5        .root.next.next.next.next.next.atom.val$lhs.val$lhs.val$lhs (object)
         d5e651a0         24 java.util.regex.Pattern$1        .root.next.next.next.next.next.atom.val$lhs.val$lhs.val$rhs (object)
         d5e651b8         24 java.util.regex.Pattern$5        .root.next.next.next.next.next.atom.val$lhs.val$lhs (object)
         d5e651d0         24 java.util.regex.Pattern$5        .root.next.next.next.next.next.atom.val$lhs (object)
         d5e651e8         24 java.util.regex.Pattern$5        .root.next.next.next.next.next.atom (object)
         d5e65200         32 java.util.regex.Pattern$Curly    .root.next.next.next.next.next (object)
         d5e65220        120 (something else)                 (somewhere else)               (something else)
         d5e65298         24 java.util.regex.Pattern$Dollar   .root.next.next.next.next.next.next (object)

"(कुछ और)" प्रविष्टियाँ ढेर में अन्य वस्तुओं का वर्णन करती हैं जो इस ऑब्जेक्ट ग्राफ का हिस्सा नहीं हैं

सबसे अच्छा जोल प्रलेखन जोल रिपॉजिटरी में जोल के नमूने हैं । नमूने आम जोल के संचालन को प्रदर्शित करते हैं और दिखाते हैं कि आप वीएम और कचरा कलेक्टर इंटर्नल का विश्लेषण करने के लिए जोल का उपयोग कैसे कर सकते हैं।


18
इस उत्तर में अधिक उत्थान होना चाहिए। निश्चित रूप से जाँच करने के लिए एक बहुत अच्छा विकल्प। EDIT: जाँच की गई कि यह इस साल जोड़ा गया था जबकि प्रश्न '08 में पूछा गया था। इस समय ओपी ने जो पूछा, वह करने के लिए शायद सबसे अच्छा और आसान विकल्प।
किराए


2
ऑब्जेक्ट "obj" के उपयोग का आकार निर्धारित करने के लिए: org.openjdk.jol.info.GraphLayout.parseInstance (obj) .totalSize ();
ताक़त

ध्यान दें कि vmDetailsअब है VM.current().details()
Miha_x64

बाहर की जाँच करें GraphLayout.parseInstance(instance).toFootprint()मैंने इसे ऑब्जेक्ट साइज़ को समझने के लिए अधिक उपयोगी पाया
मूसन

81

मुझे गलती से एक java class "jdk.nashorn.internal.ir.debug.ObjectSizeCalculator" मिला, जो पहले से ही jdk में है, जिसका उपयोग करना आसान है और किसी वस्तु के आकार को निर्धारित करने के लिए काफी उपयोगी लगता है।

System.out.println(ObjectSizeCalculator.getObjectSize(new gnu.trove.map.hash.TObjectIntHashMap<String>(12000, 0.6f, -1)));
System.out.println(ObjectSizeCalculator.getObjectSize(new HashMap<String, Integer>(100000)));
System.out.println(ObjectSizeCalculator.getObjectSize(3));
System.out.println(ObjectSizeCalculator.getObjectSize(new int[]{1, 2, 3, 4, 5, 6, 7 }));
System.out.println(ObjectSizeCalculator.getObjectSize(new int[100]));

परिणाम:

164192
48
16
48
416

3
यहाँ भी, मैं ऊपर प्रस्तावित अन्य समाधानों की कोशिश कर रहा था और ObjectSizeCalculator के पार आया था। मेरा मानना ​​है कि किसी ने भी उल्लेख नहीं किया है क्योंकि यह हाल ही में JDK 8 पर प्रोजेक्ट नैशॉर्न के हिस्से के रूप में पेश किया गया था । हालाँकि मुझे वेब पर इस वर्ग के बारे में कोई आधिकारिक दस्तावेज नहीं मिला है।
हेनरिक गोंटिजो

यह स्ट्रिंग की लंबाई पर विचार नहीं करता है। क्या यह केवल स्टैक पर आकार के बारे में है?
jontejj

1
मेरे पास एक हैशमप है, जहाँ com.carrotsearch.RamUsageEstimator, ObjectSizeCalculator के आधे हिस्से के बारे में देता है। कोनसा वाला सत्य है? - कौन सा अधिक विश्वसनीय है?
बडेरा

9
ध्यान दें कि ObjectSizeCalculatorकेवल हॉटस्पॉट वीएम पर समर्थित है
kellanburket

74

कुछ साल पहले Javaworld के पास समग्र और संभावित रूप से नेस्टेड जावा ऑब्जेक्ट्स के आकार का निर्धारण करने पर एक लेख था , वे मूल रूप से जावा में एक साइज़ोफ़ () कार्यान्वयन बनाने के माध्यम से चलते हैं। दृष्टिकोण मूल रूप से अन्य काम पर बनाता है जहां लोगों ने प्रायोगिक और ठेठ जावा वस्तुओं के आकार की प्रयोगात्मक रूप से पहचान की और फिर उस ज्ञान को एक ऐसी विधि पर लागू किया, जो कुल आकार को मिलान करने के लिए एक वस्तु ग्राफ पर पुनरावृत्ति करता है।

यह हमेशा मूल सी कार्यान्वयन की तुलना में कुछ हद तक कम सटीक होता है क्योंकि चीजें केवल एक वर्ग के पर्दे के पीछे चल रही होती हैं, लेकिन यह एक अच्छा संकेतक होना चाहिए।

वैकल्पिक रूप से एक SourceForge परियोजना को उचित आकार कहा जाता है जो एक आकार () कार्यान्वयन के साथ एक Java5 पुस्तकालय प्रदान करता है।

पुनश्च क्रमबद्धता दृष्टिकोण का उपयोग न करें, क्रमबद्ध वस्तु के आकार और जीवित रहने पर इसकी खपत की मात्रा के बीच कोई संबंध नहीं है।


6
आकार की उपयोगिता शायद सबसे तेज़ तरीका है। यह मूल रूप से स्टीफन ने कहा है, लेकिन पहले से ही उपयोग के लिए तैयार जार में पैक किया गया है।
अलेक्जेंड्रे एल

62

सबसे पहले "ऑब्जेक्ट का आकार" जावा में एक अच्छी तरह से परिभाषित अवधारणा नहीं है। आप ऑब्जेक्ट का मतलब खुद कर सकते हैं, सिर्फ उसके सदस्यों के साथ, ऑब्जेक्ट और सभी ऑब्जेक्ट्स जो इसे संदर्भित करता है (संदर्भ ग्राफ)। आप स्मृति में आकार या डिस्क पर आकार का मतलब कर सकते हैं। और जेवीएम को स्ट्रिंग्स जैसी चीजों का अनुकूलन करने की अनुमति है।

इसलिए जेवीएम से पूछने का एकमात्र सही तरीका है, एक अच्छे प्रोफाइलर के साथ (मैं आपका उपयोग करता हूं ), जो कि शायद आप नहीं चाहते।

हालांकि, ऊपर दिए गए विवरण से ऐसा लगता है कि प्रत्येक पंक्ति स्व-निहित होगी, और एक बड़ी निर्भरता का पेड़ नहीं होगा, इसलिए अधिकांश जेवीएम पर क्रमांकन विधि एक अच्छा सन्निकटन होगी। इसे करने का सबसे आसान तरीका इस प्रकार है:

 Serializable ser;
 ByteArrayOutputStream baos = new ByteArrayOutputStream();
 ObjectOutputStream oos = new ObjectOutputStream(baos);
 oos.writeObject(ser);
 oos.close();
 return baos.size();

याद रखें कि यदि आपके पास सामान्य संदर्भ वाली वस्तुएं हैं, तो यह सही परिणाम नहीं देगा, और क्रमबद्धता का आकार हमेशा स्मृति में आकार से मेल नहीं खाएगा, लेकिन यह एक अच्छा सन्निकटन है। यदि आप बाइटएयरऑरेप्यूटस्ट्रीमस्ट्रीम साइज़ को एक समझदार मान के साथ शुरू करते हैं तो कोड थोड़ा अधिक कुशल होगा।


2
मुझे यह तरीका पसंद है। वस्तु आकार के संदर्भ में आप कितनी दूर जा चुके हैं।
बर्लिन ब्राउन

1
बहुत सरल और प्रभावी। अन्य विधियां भी गड़बड़ हैं (विशेष रूप से ग्रहण आरसीपी के अंदर)। धन्यवाद।
मार्कोलोप्स

19
Serialization क्षणिक चर का ट्रैक नहीं रखेगा, और डिफ़ॉल्ट क्रमांकन विधि UTF-8 में तार लिखती है, इसलिए कोई भी ANSI वर्ण केवल एक बाइट लेगा। यदि आपके पास कई तार हैं, तो आपका आकार इतना बेकार हो जाएगा जितना कि बेकार होगा।
TMN

1
हालांकि यह सटीक आकार नहीं दे सकता है, मेरी जरूरतों के लिए मुझे केवल 2 ऑब्जेक्ट के बीच तुलना की आवश्यकता है और SizeOf एक वेब ऐप से आरंभ नहीं करेगा। धन्यवाद!
इसहाक

1
YourKit की अच्छी सिफारिश । अन्य विकल्प हैं VirtualVM और jvmmonitor
angelcervera

38

यदि आप जानना चाहते हैं कि आपके JVM में कितनी मेमोरी का उपयोग किया जा रहा है, और कितना मुफ्त है, तो आप कुछ इस तरह की कोशिश कर सकते हैं:

// Get current size of heap in bytes
long heapSize = Runtime.getRuntime().totalMemory();

// Get maximum size of heap in bytes. The heap cannot grow beyond this size.
// Any attempt will result in an OutOfMemoryException.
long heapMaxSize = Runtime.getRuntime().maxMemory();

// Get amount of free memory within the heap in bytes. This size will increase
// after garbage collection and decrease as new objects are created.
long heapFreeSize = Runtime.getRuntime().freeMemory();

संपादित करें: मैंने सोचा कि यह सहायक हो सकता है क्योंकि प्रश्न लेखक ने यह भी कहा कि वह तर्क को पसंद करेगा जो "संभव के रूप में कई पंक्तियों को पढ़ता है जब तक मैंने 32 एमबी मेमोरी का उपयोग नहीं किया है।"


24
यह एक अच्छा समाधान नहीं है, जैसा कि आप कभी नहीं जानते हैं कि कचरा इकट्ठा कब होगा, या एक बार में ढेर को कितनी अतिरिक्त मेमोरी आवंटित की जाएगी।
निक फोर्टेस्क्यू

5
यह सच है, और मैं इस पोस्ट के मुख्य प्रश्न को संबोधित करने का इरादा नहीं करूंगा, लेकिन यह उसे प्रोग्रामेटिक रूप से जानने में मदद कर सकता है जब वह अधिकतम हीप आकार को मारने के लिए कुछ हद तक बंद हो रहा है।
मैट बी

1
इस समाधान की अन्य समस्या तब है जब आप एक बहु-थ्रेड वातावरण (जैसे वेब सर्वर) में हैं। यह संभव है कि अन्य थ्रेड निष्पादन और मेमोरी की खपत में थे। इस सन्निकटन के साथ आपके सभी वर्चुअल मशीन में उपयोग की गई मेमोरी की गणना कर रहे हैं।
फरिश्ता

1
एक और नुकसान यह है कि freeMemory एक सन्निकटन देता है। Javax.crypto.Cipher ऑब्जेक्ट बनाने का प्रयास करें। दो कॉल के बीच अंतर freeMemory (एक साइफर के आकार का अनुमान लगाने के लिए) स्थिर नहीं है!
यूजेन

1
मेरा मानना ​​है कि आप एक कचरा संग्रह को मजबूर कर सकते हैं , इसलिए आप इस दृष्टिकोण में कुछ सामान कर सकते हैं।
15

24

जब मैंने ट्विटर पर काम किया, तब मैंने गहरी वस्तु के आकार की गणना के लिए एक उपयोगिता लिखी। यह विभिन्न मेमोरी मॉडल (32-बिट, संपीड़ित ऊप्स, 64-बिट) को ध्यान में रखता है, पैडिंग, उपवर्ग पैडिंग, परिपत्र डेटा संरचनाओं और सरणियों पर सही ढंग से काम करता है। आप इसे केवल एक .java फ़ाइल संकलित कर सकते हैं; इसकी कोई बाहरी निर्भरता नहीं है:

https://github.com/twitter/commons/blob/master/src/java/com/twitter/common/objectsize/ObjectSizeCalculator.java


1
Szia! मैं आपकी प्रस्तुति को भी चिल्लाना पसंद करूंगा : विभिन्न डेटा-संरचना निर्णयों की लागत के लिए एक सहज अनुभव प्राप्त करने में मदद करने के लिए स्लाइड 15-20 महान हैं। पोस्ट करने के लिए धन्यवाद!
ल्यूक उशरवुड

16
"इसकी कोई बाहरी निर्भरता नहीं है" - अमरूद कब से बाहरी निर्भरता नहीं है?
l4mpi


गुवा एक बाहरी निर्भरता है।
मर्ट सीरीमर

18

अधिकांश अन्य उत्तर उथले आकार प्रदान करते हैं - जैसे बिना किसी कुंजी या मूल्यों के बिना हाशप का आकार, जो संभवत: वह नहीं है जो आप चाहते हैं।

जैम प्रोजेक्ट ऊपर java.lang.instrumentation पैकेज का उपयोग करता है, लेकिन पेड़ पर चलता है और इसलिए आपको गहरी मेमोरी का उपयोग कर सकता है।

new MemoryMeter().measureDeep(myHashMap);

https://github.com/jbellis/jamm

MemoryMeter का उपयोग करने के लिए, "-javaagent: /jamm.jar" के साथ JVM शुरू करें


11

आपको प्रतिबिंब का उपयोग करके वस्तुओं को चलना होगा। सावधान रहें जैसे आप करते हैं:

  • बस एक वस्तु आवंटित करने से जेवीएम में कुछ ओवरहेड होता है। राशि JVM द्वारा भिन्न होती है, इसलिए आप इस मान को एक पैरामीटर बना सकते हैं। कम से कम इसे एक स्थिर (8 बाइट्स?) बनाएं और आवंटित कुछ भी लागू करें।
  • सिर्फ इसलिए byteकि सैद्धांतिक रूप से 1 बाइट का मतलब यह नहीं है कि यह स्मृति में सिर्फ एक लेता है।
  • ऑब्जेक्ट संदर्भों में लूप होंगे, इसलिए आपको अनंत लूप को खत्म करने के लिए तुलनित्र के रूप में ऑब्जेक्ट-HashMap इक्वल्स का उपयोग करके एक या सोमेसच रखना होगा ।

@jodonnell: मुझे आपके समाधान की सादगी पसंद है, लेकिन कई ऑब्जेक्ट्स Serializable नहीं हैं (इसलिए यह अपवाद को फेंक देगा), फ़ील्ड क्षणिक हो सकते हैं, और ऑब्जेक्ट मानक विधियों को ओवरराइड कर सकते हैं।


जावा विशिष्टता में परिभाषित विभिन्न प्राइमेटीज़ के आकार नहीं हैं? (§2.4.1)
एरिक्सन

4
"कितनी स्मृति पर कब्जा करता है," के अर्थ में नहीं है, जो कि सवाल है। केवल इस अर्थ में कि वे कैसे काम करते हैं। उदाहरण के लिए, बाइट्स, वर्ण, और शॉर्ट्स, जावा ढेर पर एक पूरे शब्द का समय लग भले ही वे आदि .. गोलाई के साथ काम
जेसन कोहेन

1
यह आकार को मापने के समान लगता है, जैसा कि हेंज ने अपने न्यूज़लेटर # 78 में दिखाया है: javaspecialists.eu/archive/Issue078.html । मै उसका इस्तेमाल किया। उनका दृष्टिकोण काम करता है।
पीटर कोफ्लर

8

आपको इसे एक उपकरण के साथ मापना होगा, या इसे हाथ से अनुमान लगाना होगा, और यह उस जेवीएम पर निर्भर करता है जिसका आप उपयोग कर रहे हैं।

प्रति वस्तु पर कुछ निश्चित उपरि है। यह JVM- विशिष्ट है, लेकिन मैं आमतौर पर 40 बाइट्स का अनुमान लगाता हूं। फिर आपको कक्षा के सदस्यों को देखना होगा। ऑब्जेक्ट संदर्भ एक 32-बिट (64-बिट) जेवीएम में 4 (8) बाइट्स हैं। आदिम प्रकार हैं:

  • बूलियन और बाइट: 1 बाइट
  • चार और छोटा: 2 बाइट्स
  • int और फ्लोट: 4 बाइट्स
  • लंबी और दोहरी: 8 बाइट्स

एरे उसी नियमों का पालन करता है; वह है, यह एक वस्तु संदर्भ है ताकि आपकी वस्तु में 4 (या 8) बाइट्स हो, और फिर इसकी लंबाई इसके तत्व के आकार से गुणा हो।

यह करने के लिए कॉल के साथ प्रोग्रामेटिक रूप से करने की कोशिश Runtime.freeMemory()सिर्फ आपको बहुत सटीकता नहीं देती है, क्योंकि कचरा कलेक्टर के लिए अतुल्यकालिक कॉल आदि, ढेर को प्रोफाइल के साथ -runhprof या अन्य टूल आपको सबसे सटीक परिणाम देगा।


@erickson मैं sizeof (बूलियन) == 1 के बारे में निश्चित नहीं होगा जो इस थ्रेड को देख रहा है ( stackoverflow.com/questions/1907318/… )। क्या आप कृपया इस पर टिप्पणी कर सकते हैं?
dma_k

2
@dma_k, जावा में वास्तव में असली बूलियन नहीं हैं। बूलियन का आकार सरणियों के बाहर 4bytes और भीतर 1byte है boolean[]। वास्तव में सभी आदिम गैर दोहरे / लंबे प्रकार 4 बाइट्स हैं। उत्तरार्द्ध 8 हैं (उत्तर गलत तरीके से उन्हें 4 के रूप में भी डालता है)
bestsss

@bestsss: अधिक सटीक होने के लिए, न्यूनतम मेमोरी आवंटन जेवीएम के मंच और कार्यान्वयन पर निर्भर करता है। साथ ही ढेर पर वस्तुओं को गठबंधन किया जाता है, इसलिए सभी आकारों को समेटने के बाद एक को गोल करने की आवश्यकता होती है।
dma_k

6

java.lang.instrument.Instrumentationवर्ग एक जावा वस्तु के आकार पाने के लिए एक अच्छा तरीका प्रदान करता है, लेकिन यह एक को परिभाषित करने की आवश्यकता है premainऔर एक जावा एजेंट के साथ अपने कार्यक्रम चलाते हैं। यह बहुत उबाऊ है जब आपको किसी एजेंट की आवश्यकता नहीं होती है और फिर आपको अपने आवेदन के लिए एक डमी जार एजेंट प्रदान करना होगा।

इसलिए मुझे Unsafeक्लास से एक वैकल्पिक समाधान मिला sun.misc। इसलिए, प्रोसेसर आर्किटेक्चर के अनुसार ऑब्जेक्ट्स को संरेखित करने पर विचार करना और अधिकतम फ़ील्ड ऑफ़सेट की गणना करना, आप जावा ऑब्जेक्ट के आकार को माप सकते हैं। नीचे दिए गए उदाहरण में मैं ऑब्जेक्ट का UtilUnsafeसंदर्भ प्राप्त करने के लिए एक सहायक वर्ग का उपयोग करता हूं sun.misc.Unsafe

private static final int NR_BITS = Integer.valueOf(System.getProperty("sun.arch.data.model"));
private static final int BYTE = 8;
private static final int WORD = NR_BITS/BYTE;
private static final int MIN_SIZE = 16; 

public static int sizeOf(Class src){
    //
    // Get the instance fields of src class
    // 
    List<Field> instanceFields = new LinkedList<Field>();
    do{
        if(src == Object.class) return MIN_SIZE;
        for (Field f : src.getDeclaredFields()) {
            if((f.getModifiers() & Modifier.STATIC) == 0){
                instanceFields.add(f);
            }
        }
        src = src.getSuperclass();
    }while(instanceFields.isEmpty());
    //
    // Get the field with the maximum offset
    //  
    long maxOffset = 0;
    for (Field f : instanceFields) {
        long offset = UtilUnsafe.UNSAFE.objectFieldOffset(f);
        if(offset > maxOffset) maxOffset = offset; 
    }
    return  (((int)maxOffset/WORD) + 1)*WORD; 
}
class UtilUnsafe {
    public static final sun.misc.Unsafe UNSAFE;

    static {
        Object theUnsafe = null;
        Exception exception = null;
        try {
            Class<?> uc = Class.forName("sun.misc.Unsafe");
            Field f = uc.getDeclaredField("theUnsafe");
            f.setAccessible(true);
            theUnsafe = f.get(uc);
        } catch (Exception e) { exception = e; }
        UNSAFE = (sun.misc.Unsafe) theUnsafe;
        if (UNSAFE == null) throw new Error("Could not obtain access to sun.misc.Unsafe", exception);
    }
    private UtilUnsafe() { }
}

दिलचस्प दृष्टिकोण, लेकिन क्या यह वस्तु और उसके खेतों का भंडारण खंडित नहीं है?
निकोलज

हां और मुझे कोई जेवीएम कार्यान्वयन नहीं पता है जो इस तरह के विखंडन को बनाता है।
मिगुएल गंबो

मुझे समझ नहीं आ रहा है। विखंडन एक विकल्प नहीं है :) आइए ऑब्जेक्ट C का उदाहरण लेते हैं जो वस्तुओं के क्षेत्र ए और बी के रूप में संग्रहीत होता है। क्या यह पूरी चीज़ को A या B में स्थानांतरित नहीं करता है?
निकोलज

क्षमा करें, लेकिन मैं आपकी बात नहीं समझ रहा हूं। मेरी व्याख्या के अनुसार, जावा में ऑब्जेक्ट्स को अन्य ऑब्जेक्ट्स के अंदर स्टोर नहीं किया जा सकता है, जैसे कि C स्ट्रक्चर्स में या .Net में वैल्यू टाइप्स के साथ होता है। इसलिए जब आप कहते हैं: "ऑब्जेक्ट C जो ऑब्जेक्ट A और B के फ़ील्ड के रूप में संग्रहीत है" इसका मतलब है कि ऑब्जेक्ट A और B में फ़ील्ड हैं जो ऑब्जेक्ट C पर संदर्भ (पॉइंटर्स) को स्टोर करते हैं। तब A और B का आकार बराबर होता है। उस फ़ील्ड की ऑफ़सेट सी। के संदर्भ (पॉइंटर) का आकार, सी। और संदर्भ का आकार एक शब्द का आकार है।
मिगेल गंबा

ओह, ठीक है, हम उथले आकार के बारे में बात कर रहे हैं। मेरी गलती।
निकोलज

6

वहाँ भी है मेमोरी Measurer पर उपकरण (पूर्व में गूगल कोड , पर अब GitHub , जो सरल और वाणिज्यिक के अनुकूल के तहत प्रकाशित किया है) अपाचे 2.0 लाइसेंस , के रूप में एक में चर्चा की समान प्रश्न

यदि आपको मेमोरी बाइट खपत को मापना है, तो भी, यह जावा दुभाषिया को एक कमांड-लाइन तर्क की आवश्यकता है, लेकिन अन्यथा यह ठीक काम करता है, कम से कम परिदृश्यों में मैंने इसका उपयोग किया है।


4

इंस्ट्रूमेंटेशन के साथ गड़बड़ करने के लिए और बिना किसी वस्तु के बाइट-सटीक आकार को जानने की आवश्यकता नहीं है, आप निम्नलिखित दृष्टिकोण के साथ जा सकते हैं:

System.gc();
Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();

do your job here

System.gc();
Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();

इस तरह से आप पहले और बाद में उपयोग की गई मेमोरी को पढ़ते हैं, और उपयोग की गई मेमोरी को प्राप्त करने से ठीक पहले जीसी को कॉल करते हुए आप "शोर" को लगभग 0 से कम कर देते हैं।

अधिक विश्वसनीय परिणाम के लिए आप अपनी नौकरी को n बार चला सकते हैं, और फिर उपयोग की गई मेमोरी को n से विभाजित कर सकते हैं, जिससे एक रन में कितनी स्मृति प्राप्त होती है। और भी, आप पूरी चीज़ को अधिक बार चला सकते हैं और एक औसत बना सकते हैं।


5
क्या System.gc()आप जीसी को सूचित नहीं करना चाहते हैं? यह गारंटी नहीं है कि जीसी को बिल्कुल बुलाया जाता है।
रेलडेक्स

@बहुत अच्छे। यह सुरक्षित नहीं है क्योंकि आप कभी नहीं कर सकते हैं कि जीसी आपकी लाइनों के बीच स्मृति को प्रभावित करता है या प्रभावित करता है। तो "दो" मुक्त तरीकों के बीच जीसी अधिक स्थान को मुक्त कर सकता है जिसे आप इस तरह से नहीं मानते हैं कि आपकी वस्तु छोटी दिखाई देगी
मर्ट सीरीमर

@MertSerimer "सुरक्षित नहीं है" मेरे लिए पूरे भिन्न स्तर पर है: कम से कम यह इतना सटीक नहीं है, जैसा कि मैंने भी कहा है। इसके अलावा, आप जीसी (रेलडेक्स के अनुसार) ड्राइव नहीं कर सकते, लेकिन इस मामले के लिए भी मैंने इसे एक चक्र में सम्मिलित करने का सुझाव दिया था। यह सिर्फ एक त्वरित और गंदा और अनुमानित प्रणाली है जो काम करता है अगर परिणाम बहुत विश्वसनीय होने की आवश्यकता नहीं है, जैसा कि कहा गया है।
वास्तव में

इसके साथ कई समस्याएं हैं लेकिन यह आपको एक अच्छा स्वैग देता है।
markthegrea

3

यहाँ एक उपयोगिता है जो मैंने 32-बिट, 64-बिट और 64-बिट को संकुचित OOP से निपटने के लिए कुछ लिंक किए गए उदाहरणों का उपयोग करके की है। इसका उपयोग करता है sun.misc.Unsafe

इसका उपयोग Unsafe.addressSize()मूल सूचक Unsafe.arrayIndexScale( Object[].class )के आकार और जावा संदर्भ के आकार के लिए किया जाता है।

यह किसी वस्तु के आधार आकार का पता लगाने के लिए एक ज्ञात वर्ग के क्षेत्र ऑफसेट का उपयोग करता है।

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.IdentityHashMap;
import java.util.Stack;
import sun.misc.Unsafe;

/** Usage: 
 * MemoryUtil.sizeOf( object )
 * MemoryUtil.deepSizeOf( object )
 * MemoryUtil.ADDRESS_MODE
 */
public class MemoryUtil
{
    private MemoryUtil()
    {
    }

    public static enum AddressMode
    {
        /** Unknown address mode. Size calculations may be unreliable. */
        UNKNOWN,
        /** 32-bit address mode using 32-bit references. */
        MEM_32BIT,
        /** 64-bit address mode using 64-bit references. */
        MEM_64BIT,
        /** 64-bit address mode using 32-bit compressed references. */
        MEM_64BIT_COMPRESSED_OOPS
    }

    /** The detected runtime address mode. */
    public static final AddressMode ADDRESS_MODE;

    private static final Unsafe UNSAFE;

    private static final long ADDRESS_SIZE; // The size in bytes of a native pointer: 4 for 32 bit, 8 for 64 bit
    private static final long REFERENCE_SIZE; // The size of a Java reference: 4 for 32 bit, 4 for 64 bit compressed oops, 8 for 64 bit
    private static final long OBJECT_BASE_SIZE; // The minimum size of an Object: 8 for 32 bit, 12 for 64 bit compressed oops, 16 for 64 bit
    private static final long OBJECT_ALIGNMENT = 8;

    /** Use the offset of a known field to determine the minimum size of an object. */
    private static final Object HELPER_OBJECT = new Object() { byte b; };


    static
    {
        try
        {
            // Use reflection to get a reference to the 'Unsafe' object.
            Field f = Unsafe.class.getDeclaredField( "theUnsafe" );
            f.setAccessible( true );
            UNSAFE = (Unsafe) f.get( null );

            OBJECT_BASE_SIZE = UNSAFE.objectFieldOffset( HELPER_OBJECT.getClass().getDeclaredField( "b" ) );

            ADDRESS_SIZE = UNSAFE.addressSize();
            REFERENCE_SIZE = UNSAFE.arrayIndexScale( Object[].class );

            if( ADDRESS_SIZE == 4 )
            {
                ADDRESS_MODE = AddressMode.MEM_32BIT;
            }
            else if( ADDRESS_SIZE == 8 && REFERENCE_SIZE == 8 )
            {
                ADDRESS_MODE = AddressMode.MEM_64BIT;
            }
            else if( ADDRESS_SIZE == 8 && REFERENCE_SIZE == 4 )
            {
                ADDRESS_MODE = AddressMode.MEM_64BIT_COMPRESSED_OOPS;
            }
            else
            {
                ADDRESS_MODE = AddressMode.UNKNOWN;
            }
        }
        catch( Exception e )
        {
            throw new Error( e );
        }
    }


    /** Return the size of the object excluding any referenced objects. */
    public static long shallowSizeOf( final Object object )
    {
        Class<?> objectClass = object.getClass();
        if( objectClass.isArray() )
        {
            // Array size is base offset + length * element size
            long size = UNSAFE.arrayBaseOffset( objectClass )
                    + UNSAFE.arrayIndexScale( objectClass ) * Array.getLength( object );
            return padSize( size );
        }
        else
        {
            // Object size is the largest field offset padded out to 8 bytes
            long size = OBJECT_BASE_SIZE;
            do
            {
                for( Field field : objectClass.getDeclaredFields() )
                {
                    if( (field.getModifiers() & Modifier.STATIC) == 0 )
                    {
                        long offset = UNSAFE.objectFieldOffset( field );
                        if( offset >= size )
                        {
                            size = offset + 1; // Field size is between 1 and PAD_SIZE bytes. Padding will round up to padding size.
                        }
                    }
                }
                objectClass = objectClass.getSuperclass();
            }
            while( objectClass != null );

            return padSize( size );
        }
    }


    private static final long padSize( final long size )
    {
        return (size + (OBJECT_ALIGNMENT - 1)) & ~(OBJECT_ALIGNMENT - 1);
    }


    /** Return the size of the object including any referenced objects. */
    public static long deepSizeOf( final Object object )
    {
        IdentityHashMap<Object,Object> visited = new IdentityHashMap<Object,Object>();
        Stack<Object> stack = new Stack<Object>();
        if( object != null ) stack.push( object );

        long size = 0;
        while( !stack.isEmpty() )
        {
            size += internalSizeOf( stack.pop(), stack, visited );
        }
        return size;
    }


    private static long internalSizeOf( final Object object, final Stack<Object> stack, final IdentityHashMap<Object,Object> visited )
    {
        // Scan for object references and add to stack
        Class<?> c = object.getClass();
        if( c.isArray() && !c.getComponentType().isPrimitive() )
        {
            // Add unseen array elements to stack
            for( int i = Array.getLength( object ) - 1; i >= 0; i-- )
            {
                Object val = Array.get( object, i );
                if( val != null && visited.put( val, val ) == null )
                {
                    stack.add( val );
                }
            }
        }
        else
        {
            // Add unseen object references to the stack
            for( ; c != null; c = c.getSuperclass() )
            {
                for( Field field : c.getDeclaredFields() )
                {
                    if( (field.getModifiers() & Modifier.STATIC) == 0 
                            && !field.getType().isPrimitive() )
                    {
                        field.setAccessible( true );
                        try
                        {
                            Object val = field.get( object );
                            if( val != null && visited.put( val, val ) == null )
                            {
                                stack.add( val );
                            }
                        }
                        catch( IllegalArgumentException e )
                        {
                            throw new RuntimeException( e );
                        }
                        catch( IllegalAccessException e )
                        {
                            throw new RuntimeException( e );
                        }
                    }
                }
            }
        }

        return shallowSizeOf( object );
    }
}

क्या आपने मूल्यों के साथ इस वर्ग का परीक्षण किया है? मैंने कोशिश की, लेकिन मेरे लिए, गलत मान !!!।
डेबोरा

1
एक साधारण वस्तु के लिए मुझे जो मान दिए गए थे वे सही थे, लेकिन 10 के कारक द्वारा 1mio ऑब्जेक्ट वाली सूची के लिए बंद कर दिया। फिर भी, बहुत अच्छा काम!
माइकल बॉकलिंग

दिलचस्प। मैंने इसे JDK7u67, Windows 7 x64 और Linux 2.6.16 / x86_64 पर, 32bit / 64bit / oop एड्रेस मोड का उपयोग करके परीक्षण किया है। मैंने इसकी तुलना ग्रहण मेमोरी एनालाइज़र 1.3.x में विश्लेषण किए गए मेमोरी डंप से की है। आप किस सेटअप का उपयोग कर रहे हैं? क्या आपके पास एक विशिष्ट उदाहरण है जो मैं कोशिश कर सकता हूं?
dlaudams

सबसे अच्छा विकल्प मैं कर सकता हूं। मैं नहीं कर सकते का उपयोग Instrumentationक्योंकि मैं बिल्ला शुरू नहीं करते हैं, ObjectSizeCalculatorक्योंकि वीएम प्रकार (हॉटस्पॉट) और की नहीं यकीन है कि JOLbacouse वसंत सेम। मैं इसका इस्तेमाल करता हूं और क्लास और एनम की अनदेखी करने के लिए सिंगलटन वाइज AbstractRefreshableApplicationContext.getBeanFactory().getSingletonMutex()और रिफ्लेक्टर internalSizeOfकोड को अनदेखा करने के लिए दूसरा पैरामीटर जोड़ता हूं
Perlos

परिणामों की तुलना करने के लिए ObjectSizeCalculator (संपूर्ण सर्वर 1GB से 10s की गणना करें) का उपयोग करें। JOL कारण MemError (6GB को नहीं पकड़ा जाएगा) और मुझे एक ही परिणाम नहीं मिलता है, शायद इसलिए।
Perlos

3

मैं एक ऑब्जेक्ट आकार के रनटाइम गणना की तलाश कर रहा था जो निम्नलिखित आवश्यकताओं को पूरा करता है:

  • इंस्ट्रूमेंटेशन को शामिल करने की आवश्यकता के साथ रनटाइम पर उपलब्ध है।
  • जावा 9+ के साथ Unsafe तक पहुंच के बिना काम करता है।
  • केवल कक्षा पर आधारित है। नहीं एक गहरी sizeOf जो स्ट्रिंग स्ट्रिंग लंबाई, सरणी लंबाई, आदि को ध्यान में रखता है।

निम्नलिखित मूल जावा विशेषज्ञ लेख के मूल कोड ( https://www.javaspecialists.eu/archive/Issue078.html ) पर आधारित है और इस प्रश्न के एक अन्य उत्तर में असुरक्षित संस्करण से कुछ बिट्स हैं।

मुझे आशा है कि किसी को यह उपयोगी लगता है।

public class JavaSize {

private static final int NR_BITS = Integer.valueOf(System.getProperty("sun.arch.data.model"));
private static final int BYTE = 8;
private static final int WORD = NR_BITS / BYTE;
private static final int HEADER_SIZE = 8;

public static int sizeOf(Class<?> clazz) {
    int result = 0;

    while (clazz != null) {
        Field[] fields = clazz.getDeclaredFields();
        for (int i = 0; i < fields.length; i++) {
            if (!Modifier.isStatic(fields[i].getModifiers())) {
                if (fields[i].getType().isPrimitive()) {
                    Class<?> primitiveClass = fields[i].getType();
                    if (primitiveClass == boolean.class || primitiveClass == byte.class) {
                        result += 1;
                    } else if (primitiveClass == short.class) {
                        result += 2;
                    } else if (primitiveClass == int.class || primitiveClass == float.class) {
                        result += 4;
                    } else if (primitiveClass == double.class || primitiveClass == long.class) {
                        result += 8;
                    }

                } else {
                    // assume compressed references.
                    result += 4;
                }
            }
        }

        clazz = clazz.getSuperclass();

        // round up to the nearest WORD length.
        if ((result % WORD) != 0) {
            result += WORD - (result % WORD);
        }
    }

    result += HEADER_SIZE;

    return result;
}

}


2

कोई विधि कॉल नहीं है, यदि आप यही पूछ रहे हैं। एक छोटे से शोध के साथ, मुझे लगता है कि आप अपना खुद का लिख ​​सकते हैं। एक विशेष उदाहरण में एक निश्चित आकार होता है जो संदर्भों और आदिम मूल्यों की संख्या से अधिक होता है, उदाहरण के लिए बहीखाता डेटा। आप बस वस्तु ग्राफ पर चलेंगे। कम विविध प्रकार पंक्ति, आसान।

अगर यह बहुत धीमी है या इसके लायक होने की तुलना में अधिक परेशानी है, तो हमेशा अच्छे पुराने जमाने की पंक्ति गिनती नियम-अंगूठे की होती है।


2

मैंने मक्खी पर अनुमान लगाने के लिए एक बार एक त्वरित परीक्षण लिखा था:

public class Test1 {

    // non-static nested
    class Nested { }

    // static nested
    static class StaticNested { }

    static long getFreeMemory () {
        // waits for free memory measurement to stabilize
        long init = Runtime.getRuntime().freeMemory(), init2;
        int count = 0;
        do {
            System.out.println("waiting..." + init);
            System.gc();
            try { Thread.sleep(250); } catch (Exception x) { }
            init2 = init;
            init = Runtime.getRuntime().freeMemory();
            if (init == init2) ++ count; else count = 0;
        } while (count < 5);
        System.out.println("ok..." + init);
        return init;
    }

    Test1 () throws InterruptedException {

        Object[] s = new Object[10000];
        Object[] n = new Object[10000];
        Object[] t = new Object[10000];

        long init = getFreeMemory();

        //for (int j = 0; j < 10000; ++ j)
        //    s[j] = new Separate();

        long afters = getFreeMemory();

        for (int j = 0; j < 10000; ++ j)
            n[j] = new Nested();

        long aftersn = getFreeMemory();

        for (int j = 0; j < 10000; ++ j)
            t[j] = new StaticNested();

        long aftersnt = getFreeMemory();

        System.out.println("separate:      " + -(afters - init) + " each=" + -(afters - init) / 10000);
        System.out.println("nested:        " + -(aftersn - afters) + " each=" + -(aftersn - afters) / 10000);
        System.out.println("static nested: " + -(aftersnt - aftersn) + " each=" + -(aftersnt - aftersn) / 10000);

    }

    public static void main (String[] args) throws InterruptedException {
        new Test1();
    }

}

सामान्य अवधारणा वस्तुओं को आवंटित करने और मुक्त हीप स्थान में परिवर्तन को मापने के लिए है। कुंजी getFreeMemory(), जो जीसी चलाता है और स्थिर होने के लिए रिपोर्ट किए गए मुक्त हीप आकार की प्रतीक्षा करता है । उपरोक्त का आउटपुट है:

nested:        160000 each=16
static nested: 160000 each=16

जो हम उम्मीद करते हैं, संरेखण व्यवहार और संभव ढेर ब्लॉक हेडर ओवरहेड दिया गया है।

इंस्ट्रूमेंटेशन विधि यहां स्वीकृत उत्तर में विस्तृत है जो सबसे सटीक है। मैंने जिस विधि का वर्णन किया है वह सटीक है लेकिन केवल नियंत्रित परिस्थितियों में जहां कोई अन्य थ्रेड ऑब्जेक्ट्स का निर्माण / त्याग नहीं कर रहे हैं।


2

बस जावा विज़ुअल वीएम का उपयोग करें।

इसमें वह सब कुछ है जो आपको प्रोफ़ाइल और डिबग मेमोरी समस्याओं की आवश्यकता है।

इसमें एक OQL (ऑब्जेक्ट क्वेरी लैंग्वेज) कंसोल भी है जो आपको कई उपयोगी चीजें करने की अनुमति देता है, जिनमें से एक है sizeof(o)


1

मेरा उत्तर निक द्वारा आपूर्ति किए गए कोड पर आधारित है। यह कोड बाइट्स की कुल मात्रा को मापता है जो क्रमबद्ध ऑब्जेक्ट द्वारा कब्जा कर लिया जाता है। तो यह वास्तव में क्रमबद्धता सामान + सादे वस्तु स्मृति पदचिह्न को मापता है (उदाहरण के लिए क्रमबद्ध करें intऔर आप देखेंगे कि क्रमबद्ध बाइट्स की कुल मात्रा नहीं है 4)। इसलिए यदि आप कच्चे बाइट नंबर को अपनी वस्तु के लिए उपयोग करना चाहते हैं - तो आपको उस कोड को थोड़ा संशोधित करना होगा। इस तरह:

import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class ObjectSizeCalculator {
    private Object getFirstObjectReference(Object o) {
        String objectType = o.getClass().getTypeName();

        if (objectType.substring(objectType.length()-2).equals("[]")) {
            try {
                if (objectType.equals("java.lang.Object[]"))
                    return ((Object[])o)[0];
                else if (objectType.equals("int[]"))
                    return ((int[])o)[0];
                else
                    throw new RuntimeException("Not Implemented !");
            } catch (IndexOutOfBoundsException e) {
                return null;
            }
        }

        return o;
    } 

    public int getObjectSizeInBytes(Object o) {
        final String STRING_JAVA_TYPE_NAME = "java.lang.String";

        if (o == null)
            return 0;

        String objectType = o.getClass().getTypeName();
        boolean isArray = objectType.substring(objectType.length()-2).equals("[]");

        Object objRef = getFirstObjectReference(o);
        if (objRef != null && !(objRef instanceof Serializable))
            throw new RuntimeException("Object must be serializable for measuring it's memory footprint using this method !");

        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(o);
            oos.close();
            byte[] bytes = baos.toByteArray();

            for (int i = bytes.length - 1, j = 0; i != 0; i--, j++) {
                if (objectType != STRING_JAVA_TYPE_NAME) {
                    if (bytes[i] == 112)
                        if (isArray)
                            return j - 4;
                        else
                            return j;
                } else {
                    if (bytes[i] == 0)
                        return j - 1;
                }
            }
        } catch (Exception e) {
            return -1;
        }

        return -1;
    }    

}

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


अद्यतन: उदाहरण सरणी वस्तुओं की स्मृति पदचिह्न गणना का समर्थन करने के लिए संशोधित।


1

JetBrains IntelliJ का उपयोग करते समय, पहले फ़ाइल में "मेमोरी एजेंट संलग्न करें" सक्षम करें सेटिंग्स | निर्माण, निष्पादन, तैनाती | डीबगर।

डिबगिंग करते समय, ब्याज के एक चर पर राइट-क्लिक करें और "कैलकुलेटेड रिटायर्ड साइज" चुनें: परिकलित आकार की गणना करें


0

आप एक ढेर डंप (उदाहरण के लिए, जम्प के साथ) उत्पन्न कर सकते हैं और फिर ऑब्जेक्ट आकार खोजने के लिए आउटपुट का विश्लेषण कर सकते हैं। यह एक ऑफ़लाइन समाधान है, लेकिन आप उथले और गहरे आकार आदि की जांच कर सकते हैं।


0
long heapSizeBefore = Runtime.getRuntime().totalMemory();

// Code for object construction
...
long heapSizeAfter = Runtime.getRuntime().totalMemory();
long size = heapSizeAfter - heapSizeBefore;

आकार आपको ऑब्जेक्ट निर्माण के कारण jvm के मेमोरी उपयोग में वृद्धि देता है और यह आमतौर पर ऑब्जेक्ट का आकार है।


क्या होगा यदि GC वस्तु निर्माण के लिए // कोड के दौरान बीच में चलता है? अब हर समय सही परिणाम मिल सकता है।
राजुगाडू

0

यह उत्तर ऑब्जेक्ट आकार से संबंधित नहीं है, लेकिन जब आप ऑब्जेक्ट्स को समायोजित करने के लिए सरणी का उपयोग कर रहे हैं; ऑब्जेक्ट के लिए यह कितना मेमोरी साइज़ आवंटित करेगा।

तो सरणियाँ, सूची, या उन सभी संग्रह को वास्तव में वस्तुओं को संग्रहीत करने के लिए नहीं जा रहा है (केवल आदिम के समय, वास्तविक वस्तु स्मृति आकार की जरूरत है), यह केवल उन वस्तुओं के लिए संदर्भ संग्रहीत करेगा।

अब Used heap memory = sizeOfObj + sizeOfRef (* 4 bytes) in collection

  • (4/8 बाइट्स) OS (32/64 बिट) पर निर्भर करता है

पुरातन

int   [] intArray    = new int   [1]; will require 4 bytes.
long  [] longArray   = new long  [1]; will require 8 bytes.

OBJECTS

Object[] objectArray = new Object[1]; will require 4 bytes. The object can be any user defined Object.
Long  [] longArray   = new Long  [1]; will require 4 bytes.

मेरे कहने का तात्पर्य यह है कि सभी ऑब्जेक्ट REFERENCE को केवल 4 बाइट्स मेमोरी की आवश्यकता है। यह स्ट्रिंग संदर्भ या डबल ऑब्जेक्ट संदर्भ हो सकता है, लेकिन ऑब्जेक्ट निर्माण पर निर्भर करता है कि आवश्यक मेमोरी अलग-अलग होगी।

उदाहरण) यदि मैं नीचे की कक्षा के लिए ऑब्जेक्ट बनाता हूं ReferenceMemoryTestतो 4 + 4 + 4 = 12 बाइट्स मेमोरी बनाई जाएगी। जब आप संदर्भों को प्रारंभ करने का प्रयास कर रहे हों, तो स्मृति भिन्न हो सकती है।

 class ReferenceMemoryTest {
    public String refStr;
    public Object refObj;
    public Double refDoub; 
}

इसलिए जब आप ऑब्जेक्ट / रेफरेंस एरे बना रहे हैं, तो इसकी सभी सामग्री NULL रेफरेंस के साथ आ जाएगी। और हम जानते हैं कि प्रत्येक संदर्भ में 4 बाइट्स की आवश्यकता होती है।

और अंत में, नीचे दिए गए कोड के लिए मेमोरी आवंटन 20 बाइट्स है।

ReferenceMemoryTest ref1 = new ReferenceMemoryTest (); (4 (Ref1) + 12 = 16 बाइट्स) ReferenceMemoryTest ref2 = ref1; (4 (Ref2) + 16 = 20 बाइट्स)


1
4-बाइट पूर्णांक और अज्ञात आकार का ऑब्जेक्ट संदर्भ 4 बाइट्स में कैसे फिट हो सकता है?
लोर्ने का मार्किस

@ ईजेपी मेरा कहने का मतलब है कि सभी ऑब्जेक्ट की आवश्यकता को केवल 4 बाइट्स मेमोरी की आवश्यकता है। यह स्ट्रिंग संदर्भ या डबल ऑब्जेक्ट संदर्भ हो सकता है, लेकिन ऑब्जेक्ट निर्माण पर निर्भर करता है कि आवश्यक मेमोरी अलग-अलग होगी।
कानूनगो सुगुमर ४'१५

0

मान लीजिए कि मैं एक वर्ग की घोषणा करता हूं Complexजैसे:

public class Complex {

    private final long real;
    private final long imaginary;

    // omitted
}

यह देखने के लिए कि इस वर्ग के लाइव उदाहरणों के लिए कितनी मेमोरी आवंटित की गई है:

$ jmap -histo:live <pid> | grep Complex

 num     #instances         #bytes  class name (module)
-------------------------------------------------------
 327:             1             32  Complex

-4

JSONObject के लिए नीचे दिया गया कोड आपकी मदद कर सकता है।

`JSONObject.toString().getBytes("UTF-8").length`

बाइट्स में आकार देता है

मैंने इसे अपनी JSONArray ऑब्जेक्ट के साथ एक फ़ाइल में लिखकर जाँच की। यह ऑब्जेक्ट का आकार दे रहा है।


यह केवल उन वस्तुओं के लिए काम करेगा जो ज्यादातर तार हैं।
डेक्सटर लेगास्पी

-6

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

एक तरीका यह है कि आप किसी फ़ाइल में चीज़ को क्रमबद्ध करें और फ़ाइल के आकार को देखें, जैसे:

Serializable myObject;
ObjectOutputStream oos = new ObjectOutputStream (new FileOutputStream ("obj.ser"));
oos.write (myObject);
oos.close ();

बेशक, यह मानता है कि प्रत्येक वस्तु अलग है और किसी भी चीज में गैर-क्षणिक संदर्भ नहीं रखती है।

एक अन्य रणनीति यह होगी कि प्रत्येक वस्तु को लिया जाए और उसके सदस्यों की परछाईं की जाँच की जाए और आकार (बूलियन और बाइट = 1 बाइट, शॉर्ट एंड चार = 2 बाइट्स इत्यादि) को जोड़ा जाए, जिससे सदस्यता पदानुक्रम नीचे आए। लेकिन यह थकाऊ और महंगा है और यह वही काम करता है जो क्रमबद्ध रणनीति करेगी।


3
मैं इसे एक बाइट [[] को बाइटएयरऑरेपुटपुटस्ट्रीम का उपयोग करके अनुक्रमित करूँगा। यह एक फ़ाइल को लिखने की तुलना में बहुत तेज़ होगा।
ScArcher2

@KorayTugay किसी वस्तु का बाइट आकार निर्धारित करना पहले से ही एक महंगा ऑपरेशन है। आकार को निर्धारित करने के लिए डिस्क पर प्रत्येक ऑब्जेक्ट लिखना, बस इसे क्रॉल करने जा रहा है ...
हैमरएनएल

1
क्रमबद्ध ऑब्जेक्ट प्रारूप ढेर मेमोरी में ऑब्जेक्ट के प्रारूप से पूरी तरह से अलग है। सबसे विशेष रूप से, ऑब्जेक्ट के वर्ग के लिए एक डिस्क्रिप्टर (और इसके सभी क्रमिक सुपरक्लेसेस) स्ट्रीम को लिखा जाता है। इसलिए java.lang.Integerलगभग 80 बाइट्स का उत्पादन करने का एक सरल उदाहरण लिखना , जहां ढेर प्रतिनिधित्व आमतौर पर 32 है (ऑब्जेक्ट स्ट्रीम प्रतिनिधित्व के विपरीत, हीप प्रतिनिधित्व सूचक आकार और ऑब्जेक्ट संरेखण पर निर्भर करता है)। इसके विपरीत, क्रमबद्ध nullसंदर्भ में ढेर मेमोरी में चार या आठ बाइट्स के बजाय एक बाइट की आवश्यकता होती है।
होल्गर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.