在Java中,确定对象大小的最佳方法是什么?

时间:2022-09-13 09:23:18

For example, let's say I have an application that can read in a CSV file with piles of data rows. I give the user a summary of the number of rows based on types of data, but I want to make sure that I don't read in too many rows of data and cause OutOfMemoryErrors. Each row translates into an object. Is there an easy way to find out the size of that object programmatically? Is there a reference that defines how large primitive types and object references are for a VM?

例如,假设我有一个应用程序,它可以在CSV文件中读取成堆的数据行。我给用户一个基于数据类型的行数的总结,但是我希望确保我不会读取太多的数据,并导致outofmemoryerror错误。每一行转换成一个对象。有没有一种简单的方法可以通过编程方式找到对象的大小?是否有一个引用来定义VM的基本类型和对象引用的大小?

Right now, I have code that says read up to 32,000 rows, but I'd also like to have code that says read as many rows as possible until I've used 32MB of memory. Maybe that is a different question, but I'd still like to know.

现在,我有一个代码,上面写着读到32,000行,但是我也希望有代码,它说尽可能多的读取行,直到我使用32MB的内存。也许这是个不同的问题,但我还是想知道。

24 个解决方案

#1


381  

You can use the java.lang.instrument package

您可以使用java.lang。仪器包

Compile and put this class in a JAR:

编译并将这个类放入一个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);
    }
}

Add the following to your MANIFEST.MF:

将以下内容添加到您的MANIFEST.MF:

Premain-Class: ObjectSizeFetcher

Use getObjectSize:

使用getObjectSize:

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

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

Invoke with:

调用:

java -javaagent:ObjectSizeFetcherAgent.jar C

#2


66  

Some years back Javaworld had an article on determining the size of composite and potentially nested Java objects, they basically walk through creating a sizeof() implementation in Java. The approach basically builds on other work where people experimentally identified the size of primitives and typical Java objects and then apply that knowledge to a method that recursively walks an object graph to tally the total size.

几年前,Javaworld有一篇关于确定复合和潜在嵌套Java对象大小的文章,它们基本上是通过在Java中创建sizeof()实现来实现的。这种方法基本上是建立在其他工作上的,在那里,人们通过实验确定了原语和典型的Java对象的大小,然后将这些知识应用到一个递归遍历对象图的方法中,以计算总大小。

It is always going to be somewhat less accurate than a native C implementation simply because of the things going on behind the scenes of a class but it should be a good indicator.

它总是比本地C实现的精度要低,仅仅因为在一个类的场景后面发生了一些事情,但是它应该是一个好的指示器。

Alternatively a SourceForge project appropriately called sizeof that offers a Java5 library with a sizeof() implementation.

或者,一个名为sizeof的SourceForge项目提供了一个具有sizeof()实现的Java5库。

P.S. Do not use the serialization approach, there is no correlation between the size of a serialized object and the amount of memory it consumes when live.

如果不使用序列化方法,则序列化对象的大小和它所消耗的内存数量之间没有相关性。

#3


53  

You should use jol, a tool developed as part of the OpenJDK project.

您应该使用jol,作为OpenJDK项目的一部分开发的工具。

JOL (Java Object Layout) is the tiny toolbox to analyze object layout schemes in JVMs. These tools are using Unsafe, JVMTI, and Serviceability Agent (SA) heavily to decoder the actual object layout, footprint, and references. This makes JOL much more accurate than other tools relying on heap dumps, specification assumptions, etc.

JOL (Java对象布局)是用于分析jvm中对象布局方案的小工具箱。这些工具使用不安全的JVMTI和servicableagent (SA)来解码器实际的对象布局、内存占用和引用。这使得JOL比依赖堆转储、规范假设等的其他工具更准确。

To get the sizes of primitives, references and array elements, use VMSupport.vmDetails(). On Oracle JDK 1.8.0_40 running on 64-bit Windows (used for all following examples), this method returns

要获取原语、引用和数组元素的大小,请使用VMSupport.vmDetails()。在64位Windows上运行的Oracle JDK 1.8.0_40(用于所有以下示例),此方法返回。

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]

You can get the shallow size of an object instance using ClassLayout.parseClass(Foo.class).toPrintable() (optionally passing an instance to toPrintable). This is only the space consumed by a single instance of that class; it does not include any other objects referenced by that class. It does include VM overhead for the object header, field alignment and padding. For java.util.regex.Pattern:

您可以使用ClassLayout.parseClass(Foo.class).toPrintable()(可选地将一个实例传递给toPrintable)来获得对象实例的浅大小。这只是该类的单个实例所消耗的空间;它不包含该类引用的任何其他对象。它包含了对象头、字段对齐和填充的VM开销。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

You can get a summary view of the deep size of an object instance using GraphLayout.parseInstance(obj).toFootprint(). Of course, some objects in the footprint might be shared (also referenced from other objects), so it is an overapproximation of the space that could be reclaimed when that object is garbage collected. For the result of Pattern.compile("^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+$") (taken from this answer), jol reports a total footprint of 1840 bytes, of which only 72 are the Pattern instance itself.

您可以使用GraphLayout.parseInstance(obj). tofootprint()获得一个对象实例的深度大小的摘要视图。当然,内存占用中的一些对象可能是共享的(也可以从其他对象引用),因此,当该对象被垃圾收集时,它是一个可以被回收的空间的超近似值。[Pattern.compile的结果(“^ - 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)

If you instead use GraphLayout.parseInstance(obj).toPrintable(), jol will tell you the address, size, type, value and path of field dereferences to each referenced object, though that's usually too much detail to be useful. For the ongoing pattern example, you might get the following. (Addresses will likely change between runs.)

如果您使用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)

The "(something else)" entries describe other objects in the heap that are not part of this object graph.

“(其他)”条目描述堆中不属于该对象图的其他对象。

The best jol documentation is the jol samples in the jol repository. The samples demonstrate common jol operations and show how you can use jol to analyze VM and garbage collector internals.

最好的jol文档是jol存储库中的jol示例。这些示例演示了常见的jol操作,并展示了如何使用jol来分析VM和垃圾收集器内部。

#4


52  

Firstly "the size of an object" isn't a well-defined concept in Java. You could mean the object itself, with just its members, the Object and all objects it refers to (the reference graph). You could mean the size in memory or the size on disk. And the JVM is allowed to optimise things like Strings.

首先,“对象的大小”在Java中并不是一个定义良好的概念。您可以指对象本身,它的成员、对象和它引用的所有对象(引用图)。您可以指内存大小或磁盘上的大小。JVM可以优化字符串之类的东西。

So the only correct way is to ask the JVM, with a good profiler (I use YourKit), which probably isn't what you want.

因此,唯一正确的方法是询问JVM,使用一个良好的分析器(我使用您的工具包),这可能不是您想要的。

However, from the description above it sounds like each row will be self-contained, and not have a big dependency tree, so the serialization method will probably be a good approximation on most JVMs. The easiest way to do this is as follows:

但是,从上面的描述来看,每一行都是自包含的,并且没有很大的依赖树,因此序列化方法可能是大多数jvm的一个很好的近似。最简单的方法是:

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

Remember that if you have objects with common references this will not give the correct result, and size of serialization will not always match size in memory, but it is a good approximation. The code will be a bit more efficient if you initialise the ByteArrayOutputStream size to a sensible value.

请记住,如果您有一些具有公共引用的对象,这将不会给出正确的结果,而序列化的大小并不总是与内存中的大小匹配,但这是一个很好的近似。如果您将ByteArrayOutputStream大小初始化为一个合理的值,那么代码将会更高效一些。

#5


33  

If you would just like to know how much memory is being used in your JVM, and how much is free, you could try something like this:

如果您想知道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();

edit: I thought this might be helpful as the question author also stated he would like to have logic that handles "read as many rows as possible until I've used 32MB of memory."

编辑:我认为这可能是有用的,因为问题作者也说过,他希望逻辑处理“尽可能多地读取行,直到我使用32MB的内存。”

#6


31  

I accidentally found a java class "jdk.nashorn.internal.ir.debug.ObjectSizeCalculator", already in jdk, which is easy to use and seems quite useful for determining the size of an object.

我无意中发现了一个java类“jdknashorn.intern.net .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]));

results:

结果:

164192
48
16
48
416

#7


17  

Back when I worked at Twitter, I wrote a utility for calculating deep object size. It takes into account different memory models (32-bit, compressed oops, 64-bit), padding, subclass padding, works correctly on circular data structures and arrays. You can just compile this one .java file; it has no external dependencies:

当我在Twitter工作时,我写了一个实用工具来计算深度对象大小。它考虑了不同的内存模型(32位、压缩的oops、64位)、填充、子类填充,在圆形数据结构和数组中正确工作。你可以编译这个。java文件;它没有外部依赖项:

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

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

#8


12  

Much of the other answers provide shallow sizes - e.g. the size of a HashMap without any of the keys or values, which isn't likely what you want.

许多其他的答案提供了较浅的尺寸——例如,没有任何键或值的HashMap的大小,这是不太可能的。

The jamm project uses the java.lang.instrumentation package above but walks the tree and so can give you the deep memory use.

jamm项目使用java.lang。上面的仪器包,但走的树,所以可以给你深的内存使用。

new MemoryMeter().measureDeep(myHashMap);

https://github.com/jbellis/jamm

https://github.com/jbellis/jamm

#9


9  

You have to walk the objects using reflection. Be careful as you do:

你必须用反射来行走物体。你要小心:

  • Just allocating an object has some overhead in the JVM. The amount varies by JVM so you might make this value a parameter. At least make it a constant (8 bytes?) and apply to anything allocated.
  • 只分配一个对象在JVM中有一些开销。数量因JVM而异,所以您可能会使这个值成为一个参数。至少使它成为一个常量(8个字节?)并应用于任何分配的内容。
  • Just because byte is theoretically 1 byte doesn't mean it takes just one in memory.
  • 仅仅因为从理论上说,一个字节并不意味着它只需要一个内存。
  • There will be loops in object references, so you'll need to keep a HashMap or somesuch using object-equals as the comparator to eliminate infinite loops.
  • 在对象引用中会有循环,因此您需要使用对象-equals作为消除无限循环的比较器来保存HashMap或somesuch。

@jodonnell: I like the simplicity of your solution, but many objects aren't Serializable (so this would throw an exception), fields can be transient, and objects can override the standard methods.

@jodonnell:我喜欢您的解决方案的简单性,但是许多对象都不是可序列化的(因此这会引发异常),字段可以是临时的,对象可以重写标准方法。

#10


6  

You have to measure it with a tool, or estimate it by hand, and it depends on the JVM you are using.

您必须使用工具来度量它,或者手动估计它,这取决于您使用的JVM。

There is some fixed overhead per object. It's JVM-specific, but I usually estimate 40 bytes. Then you have to look at the members of the class. Object references are 4 (8) bytes in a 32-bit (64-bit) JVM. Primitive types are:

每个对象都有一些固定的开销。它是特定于jvm的,但我通常估计有40个字节。然后你要看看班上的同学。对象引用在32位(64位)JVM中是4(8)字节。基本类型是:

  • boolean and byte: 1 byte
  • 布尔和字节:1字节。
  • char and short: 2 bytes
  • char和short: 2字节。
  • int and float: 4 bytes
  • int和float: 4字节。
  • long and double: 8 bytes
  • long和double: 8字节。

Arrays follow the same rules; that is, it's an object reference so that takes 4 (or 8) bytes in your object, and then its length multiplied by the size of its element.

数组遵循相同的规则;也就是说,它是一个对象引用,在对象中使用4(或8)个字节,然后它的长度乘以它的元素的大小。

Trying to do it programmatically with calls to Runtime.freeMemory() just doesn't give you much accuracy, because of asynchronous calls to the garbage collector, etc. Profiling the heap with -Xrunhprof or other tools will give you the most accurate results.

freememory()只是没有给你太多的准确性,因为对垃圾收集器的异步调用等等。用-Xrunhprof或其他工具对堆进行分析,会得到最准确的结果。

#11


6  

There is also the Memory Measurer tool (formerly at Google Code, now on GitHub), which is simple and published under the commercial-friendly Apache 2.0 license, as discussed in a similar question.

还有一个内存测量工具(以前在谷歌代码中,现在在GitHub上),它很简单,在商业友好的Apache 2.0许可下发布,就像在类似的问题中讨论的一样。

It, too, requires a command-line argument to the java interpreter if you want to measure memory byte consumption, but otherwise seems to work just fine, at least in the scenarios I have used it.

如果您想要测量内存字节的消耗,那么它也需要java解释器的命令行参数,但是在其他情况下,至少在我使用的场景中是这样的。

#12


6  

I recommend the java-sizeof library for carrotsearch. It is very simple.

我推荐用于carrotsearch的java-sizeof库。它是非常简单的。

You can get it in maven:

你可以在maven中得到它:

 <dependency>
    <groupId>com.carrotsearch</groupId>
    <artifactId>java-sizeof</artifactId>
    <version>0.0.3</version>
</dependency>

It is only one code line that return the bytes of an object:

只有一个代码行返回一个对象的字节:

RamUsageEstimator.sizeOf(new Object());

You can see the source code at https://github.com/dweiss/java-sizeof

您可以在https://github.com/dweiss/javasizeof上看到源代码。

And there is a presentation from the author of the library http://www.slideshare.net/DawidWeiss/sizeofobject-how-much-memory-objects-take-on-jvms-and-when-this-may-matter?ref=http://cheremin.blogspot.com/2012/05/how-much-memory-objects-take-on-jvm-and.html

还有一个来自于http://www.slideshare.net/dawidweiss/sizeofobject - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

#13


5  

The java.lang.instrument.Instrumentation class provides a nice way to get the size of a Java Object, but it requires you to define a premain and run your program with a java agent. This is very boring when you do not need any agent and then you have to provide a dummy Jar agent to your application.

java.lang.instrument。工具类提供了一个获得Java对象大小的好方法,但是它要求您定义一个premain并使用Java代理运行您的程序。当您不需要任何代理时,这是非常令人厌烦的,然后您必须为您的应用程序提供一个虚拟的Jar代理。

So I got an alternative solution using the Unsafe class from the sun.misc. So, considering the objects heap alignment according to the processor architecture and calculating the maximum field offset, you can measure the size of a Java Object. In the example below I use an auxiliary class UtilUnsafe to get a reference to the sun.misc.Unsafe object.

因此,我从sun.misc得到了一个使用不安全类的替代解决方案。因此,根据处理器架构和计算最大字段偏移量来考虑对象堆对齐,您可以测量Java对象的大小。在下面的例子中,我使用一个辅助类UtilUnsafe来获取对sun.misc的引用。不安全的对象。

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() { }
}

#14


2  

I wrote a quick test once to estimate on the fly:

我曾写过一次快速测试来估算飞行时间:

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();
    }

}

General concept is allocate objects and measure change in free heap space. The key being getFreeMemory(), which requests GC runs and waits for the reported free heap size to stabilize. The output of the above is:

一般概念是在*堆空间中分配对象和度量变化。关键是getFreeMemory(),它请求GC运行并等待报告的空闲堆大小稳定。上面的输出是:

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

Which is what we expect, given alignment behavior and possible heap block header overhead.

这就是我们所期望的,给定对齐行为和可能的堆块头开销。

The instrumentation method detailed in the accepted answer here the most accurate. The method I described is accurate but only under controlled conditions where no other threads are creating/discarding objects.

该仪器方法详细的在公认的答案这里是最准确的。我描述的方法是准确的,但只有在没有其他线程创建/丢弃对象的受控条件下。

#15


2  

Here is a utility I made using some of the linked examples to handle 32-bit, 64-bit and 64-bit with compressed OOP. It uses sun.misc.Unsafe.

这里是一个实用程序,我使用一些链接的示例来处理32位、64位和64位的压缩OOP。它使用sun.misc.Unsafe。

It uses Unsafe.addressSize() to get the size of a native pointer and Unsafe.arrayIndexScale( Object[].class ) for the size of a Java reference.

它使用Unsafe.addressSize()来获取本机指针的大小和不安全。arrayIndexScale(Object[]。类)用于Java引用的大小。

It uses the field offset of a known class to work out the base size of an object.

它使用已知类的字段偏移量来计算对象的基本大小。

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 );
    }
}

#16


2  

Without having to mess with instrumentation and so on, and if you don't need to know the byte-exact size of an object, you could go with the following approach:

如果你不需要摆弄仪器等等,如果你不需要知道一个物体的字节精确大小,你可以使用下面的方法:

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

do your job here

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

This way you read the used memory before and after, and calling the GC just before getting the used memory you lower the "noise" almost to 0.

通过这种方式,您可以在使用之前和之后读取所使用的内存,并在使用内存之前调用GC,从而将“噪声”降低到几乎为0。

For a more reliable result you can run your job n times, and then divide the used memory by n, obtaining how much memory one run takes. Even more, you can run the whole thing more times and make an average.

为了获得更可靠的结果,您可以运行您的作业n次,然后将使用的内存除以n,获得一次运行所需的内存。更重要的是,你可以把整件事做的更多次,并做出一个平均值。

#17


1  

There isn't a method call, if that's what you're asking for. With a little research, I suppose you could write your own. A particular instance has a fixed sized derived from the number of references and primitive values plus instance bookkeeping data. You would simply walk the object graph. The less varied the row types, the easier.

如果这是你要的,那就没有方法调用。有一点研究,我想你可以自己写。一个特定的实例有一个固定的大小,它来自于引用的数量和原始值加上实例bookkeeping数据。你只需要走物体图。行类型越少,就越容易。

If that's too slow or just more trouble than it's worth, there's always good old-fashioned row counting rule-of-thumbs.

如果这太慢了,或者只是麻烦大于它的价值,那么总是有很好的老式的计数规则。

#18


0  

You could generate a heap dump (with jmap, for example) and then analyze the output to find object sizes. This is an offline solution, but you can examine shallow and deep sizes, etc.

您可以生成堆转储(例如使用jmap),然后分析输出以查找对象大小。这是一个离线的解决方案,但是您可以检查浅层和深度的大小,等等。

#19


0  

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

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

size gives you the increase in memory usage of the jvm due to object creation and that typically is the size of the object.

由于对象的创建,大小会增加jvm的内存使用量,而这通常是对象的大小。

#20


0  

My answer is based on the code supplied by Nick. That code measures total amount of bytes which are occupied by the serialized object. So this actually measures serialization stuff + plain object memory footprint (just serialize for example int and you will see that total amount of serialized bytes is not 4). So if you want to get raw byte number used exactly for your object - you need to modify that code a bit. Like so:

我的回答是基于Nick提供的代码。该代码度量被序列化的对象占用的总字节数。这实际上措施序列化东西+普通对象内存占用(例如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;
    }    

}

I've tested this solution with primitive types, String, and on some trivial classes. There may be not covered cases also.

我已经用基本类型、字符串和一些普通类测试了这个解决方案。也可能没有涵盖的案例。


UPDATE: Example modified to support memory footprint calculation of array objects.

更新:示例修改以支持数组对象的内存占用计算。

#21


0  

This answer is not related to Object size, but when you are using array to accommodate the objects; how much memory size it will allocate for the object.

这个答案与对象大小无关,但是当您使用数组来容纳对象时;它将为对象分配多少内存大小。

So arrays, list, or map all those collection won't be going to store objects really (only at the time of primitives, real object memory size is needed), it will store only references for those objects.

因此,数组、列表或映射所有这些集合不会真正地存储对象(只有在原语的时候,真正的对象内存大小是需要的),它将只存储这些对象的引用。

Now the Used heap memory = sizeOfObj + sizeOfRef (* 4 bytes) in collection

现在,在集合中使用的堆内存= sizeOfObj + sizeOfRef(* 4字节)。

  • (4/8 bytes) depends on (32/64 bit) OS
  • (4/8字节)取决于(32/64位)操作系统。

PRIMITIVES

原语

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.

I mean to say all the object REFERENCE needs only 4 bytes of memory. It may be String reference OR Double object reference, But depends on object creation the memory needed will vary.

我的意思是,所有对象引用只需要4个字节的内存。它可能是字符串引用或双对象引用,但是依赖于对象创建,所需的内存将会有所不同。

e.g) If i create object for the below class ReferenceMemoryTest then 4 + 4 + 4 = 12 bytes of memory will be created. The memory may differ when you are trying to initialize the references.

如果我为下面的类ReferenceMemoryTest创建对象,那么将创建4 + 4 + 4 = 12字节的内存。当您试图初始化引用时,内存可能会有所不同。

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

So when are creating object/reference array, all its contents will be occupied with NULL references. And we know each reference requires 4 bytes.

因此,当创建对象/引用数组时,所有的内容都将被空引用占据。我们知道每个引用需要4个字节。

And finally, memory allocation for the below code is 20 bytes.

最后,下面代码的内存分配是20字节。

ReferenceMemoryTest ref1 = new ReferenceMemoryTest(); ( 4(ref1) + 12 = 16 bytes) ReferenceMemoryTest ref2 = ref1; ( 4(ref2) + 16 = 20 bytes)

参考文献[参考文献];(参考文献4(ref1) + 12 = 16字节)(4(ref2) + 16 = 20字节)

#22


0  

Just use java visual VM.

只需使用java visual VM。

It has everything you need to profile and debug memory problems.

它有所有您需要的配置和调试内存问题。

It also has a OQL (Object Query Language) console which allows you to do many useful things, one of which being sizeof(o)

它还有一个OQL(对象查询语言)控制台,它允许您做许多有用的事情,其中一个是sizeof(o)

#23


-2  

The below code can help you surely.

下面的代码可以帮助您确定。

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

returns size in bytes

返回字节数

I checked it with my JSONArray object by writing it to a file. It is giving object size.

我通过将JSONArray对象写入文件来检查它。它提供对象大小。

#24


-6  

I doubt you want to do it programmatically unless you just want to do it once and store it for future use. It's a costly thing to do. There's no sizeof() operator in Java, and even if there was, it would only count the cost of the references to other objects and the size of the primitives.

我怀疑您是否想要以编程方式完成它,除非您只想做一次并存储它以备将来使用。这是一件昂贵的事情。Java中没有sizeof()操作符,即使有,它也只会计算对其他对象的引用的成本和原语的大小。

One way you could do it is to serialize the thing to a File and look at the size of the file, like this:

一种方法是将该文件序列化为文件,然后查看文件的大小,如下所示:

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

Of course, this assumes that each object is distinct and doesn't contain non-transient references to anything else.

当然,这假定每个对象都是不同的,并且不包含对其他任何东西的非瞬态引用。

Another strategy would be to take each object and examine its members by reflection and add up the sizes (boolean & byte = 1 byte, short & char = 2 bytes, etc.), working your way down the membership hierarchy. But that's tedious and expensive and ends up doing the same thing the serialization strategy would do.

另一个策略是使用每个对象并通过反射检查其成员,并将大小(boolean & byte = 1字节,short & char = 2字节,等等)添加到成员层次结构中。但这很乏味,而且代价高昂,结果就是序列化策略所做的事情。

#1


381  

You can use the java.lang.instrument package

您可以使用java.lang。仪器包

Compile and put this class in a JAR:

编译并将这个类放入一个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);
    }
}

Add the following to your MANIFEST.MF:

将以下内容添加到您的MANIFEST.MF:

Premain-Class: ObjectSizeFetcher

Use getObjectSize:

使用getObjectSize:

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

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

Invoke with:

调用:

java -javaagent:ObjectSizeFetcherAgent.jar C

#2


66  

Some years back Javaworld had an article on determining the size of composite and potentially nested Java objects, they basically walk through creating a sizeof() implementation in Java. The approach basically builds on other work where people experimentally identified the size of primitives and typical Java objects and then apply that knowledge to a method that recursively walks an object graph to tally the total size.

几年前,Javaworld有一篇关于确定复合和潜在嵌套Java对象大小的文章,它们基本上是通过在Java中创建sizeof()实现来实现的。这种方法基本上是建立在其他工作上的,在那里,人们通过实验确定了原语和典型的Java对象的大小,然后将这些知识应用到一个递归遍历对象图的方法中,以计算总大小。

It is always going to be somewhat less accurate than a native C implementation simply because of the things going on behind the scenes of a class but it should be a good indicator.

它总是比本地C实现的精度要低,仅仅因为在一个类的场景后面发生了一些事情,但是它应该是一个好的指示器。

Alternatively a SourceForge project appropriately called sizeof that offers a Java5 library with a sizeof() implementation.

或者,一个名为sizeof的SourceForge项目提供了一个具有sizeof()实现的Java5库。

P.S. Do not use the serialization approach, there is no correlation between the size of a serialized object and the amount of memory it consumes when live.

如果不使用序列化方法,则序列化对象的大小和它所消耗的内存数量之间没有相关性。

#3


53  

You should use jol, a tool developed as part of the OpenJDK project.

您应该使用jol,作为OpenJDK项目的一部分开发的工具。

JOL (Java Object Layout) is the tiny toolbox to analyze object layout schemes in JVMs. These tools are using Unsafe, JVMTI, and Serviceability Agent (SA) heavily to decoder the actual object layout, footprint, and references. This makes JOL much more accurate than other tools relying on heap dumps, specification assumptions, etc.

JOL (Java对象布局)是用于分析jvm中对象布局方案的小工具箱。这些工具使用不安全的JVMTI和servicableagent (SA)来解码器实际的对象布局、内存占用和引用。这使得JOL比依赖堆转储、规范假设等的其他工具更准确。

To get the sizes of primitives, references and array elements, use VMSupport.vmDetails(). On Oracle JDK 1.8.0_40 running on 64-bit Windows (used for all following examples), this method returns

要获取原语、引用和数组元素的大小,请使用VMSupport.vmDetails()。在64位Windows上运行的Oracle JDK 1.8.0_40(用于所有以下示例),此方法返回。

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]

You can get the shallow size of an object instance using ClassLayout.parseClass(Foo.class).toPrintable() (optionally passing an instance to toPrintable). This is only the space consumed by a single instance of that class; it does not include any other objects referenced by that class. It does include VM overhead for the object header, field alignment and padding. For java.util.regex.Pattern:

您可以使用ClassLayout.parseClass(Foo.class).toPrintable()(可选地将一个实例传递给toPrintable)来获得对象实例的浅大小。这只是该类的单个实例所消耗的空间;它不包含该类引用的任何其他对象。它包含了对象头、字段对齐和填充的VM开销。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

You can get a summary view of the deep size of an object instance using GraphLayout.parseInstance(obj).toFootprint(). Of course, some objects in the footprint might be shared (also referenced from other objects), so it is an overapproximation of the space that could be reclaimed when that object is garbage collected. For the result of Pattern.compile("^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+$") (taken from this answer), jol reports a total footprint of 1840 bytes, of which only 72 are the Pattern instance itself.

您可以使用GraphLayout.parseInstance(obj). tofootprint()获得一个对象实例的深度大小的摘要视图。当然,内存占用中的一些对象可能是共享的(也可以从其他对象引用),因此,当该对象被垃圾收集时,它是一个可以被回收的空间的超近似值。[Pattern.compile的结果(“^ - 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)

If you instead use GraphLayout.parseInstance(obj).toPrintable(), jol will tell you the address, size, type, value and path of field dereferences to each referenced object, though that's usually too much detail to be useful. For the ongoing pattern example, you might get the following. (Addresses will likely change between runs.)

如果您使用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)

The "(something else)" entries describe other objects in the heap that are not part of this object graph.

“(其他)”条目描述堆中不属于该对象图的其他对象。

The best jol documentation is the jol samples in the jol repository. The samples demonstrate common jol operations and show how you can use jol to analyze VM and garbage collector internals.

最好的jol文档是jol存储库中的jol示例。这些示例演示了常见的jol操作,并展示了如何使用jol来分析VM和垃圾收集器内部。

#4


52  

Firstly "the size of an object" isn't a well-defined concept in Java. You could mean the object itself, with just its members, the Object and all objects it refers to (the reference graph). You could mean the size in memory or the size on disk. And the JVM is allowed to optimise things like Strings.

首先,“对象的大小”在Java中并不是一个定义良好的概念。您可以指对象本身,它的成员、对象和它引用的所有对象(引用图)。您可以指内存大小或磁盘上的大小。JVM可以优化字符串之类的东西。

So the only correct way is to ask the JVM, with a good profiler (I use YourKit), which probably isn't what you want.

因此,唯一正确的方法是询问JVM,使用一个良好的分析器(我使用您的工具包),这可能不是您想要的。

However, from the description above it sounds like each row will be self-contained, and not have a big dependency tree, so the serialization method will probably be a good approximation on most JVMs. The easiest way to do this is as follows:

但是,从上面的描述来看,每一行都是自包含的,并且没有很大的依赖树,因此序列化方法可能是大多数jvm的一个很好的近似。最简单的方法是:

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

Remember that if you have objects with common references this will not give the correct result, and size of serialization will not always match size in memory, but it is a good approximation. The code will be a bit more efficient if you initialise the ByteArrayOutputStream size to a sensible value.

请记住,如果您有一些具有公共引用的对象,这将不会给出正确的结果,而序列化的大小并不总是与内存中的大小匹配,但这是一个很好的近似。如果您将ByteArrayOutputStream大小初始化为一个合理的值,那么代码将会更高效一些。

#5


33  

If you would just like to know how much memory is being used in your JVM, and how much is free, you could try something like this:

如果您想知道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();

edit: I thought this might be helpful as the question author also stated he would like to have logic that handles "read as many rows as possible until I've used 32MB of memory."

编辑:我认为这可能是有用的,因为问题作者也说过,他希望逻辑处理“尽可能多地读取行,直到我使用32MB的内存。”

#6


31  

I accidentally found a java class "jdk.nashorn.internal.ir.debug.ObjectSizeCalculator", already in jdk, which is easy to use and seems quite useful for determining the size of an object.

我无意中发现了一个java类“jdknashorn.intern.net .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]));

results:

结果:

164192
48
16
48
416

#7


17  

Back when I worked at Twitter, I wrote a utility for calculating deep object size. It takes into account different memory models (32-bit, compressed oops, 64-bit), padding, subclass padding, works correctly on circular data structures and arrays. You can just compile this one .java file; it has no external dependencies:

当我在Twitter工作时,我写了一个实用工具来计算深度对象大小。它考虑了不同的内存模型(32位、压缩的oops、64位)、填充、子类填充,在圆形数据结构和数组中正确工作。你可以编译这个。java文件;它没有外部依赖项:

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

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

#8


12  

Much of the other answers provide shallow sizes - e.g. the size of a HashMap without any of the keys or values, which isn't likely what you want.

许多其他的答案提供了较浅的尺寸——例如,没有任何键或值的HashMap的大小,这是不太可能的。

The jamm project uses the java.lang.instrumentation package above but walks the tree and so can give you the deep memory use.

jamm项目使用java.lang。上面的仪器包,但走的树,所以可以给你深的内存使用。

new MemoryMeter().measureDeep(myHashMap);

https://github.com/jbellis/jamm

https://github.com/jbellis/jamm

#9


9  

You have to walk the objects using reflection. Be careful as you do:

你必须用反射来行走物体。你要小心:

  • Just allocating an object has some overhead in the JVM. The amount varies by JVM so you might make this value a parameter. At least make it a constant (8 bytes?) and apply to anything allocated.
  • 只分配一个对象在JVM中有一些开销。数量因JVM而异,所以您可能会使这个值成为一个参数。至少使它成为一个常量(8个字节?)并应用于任何分配的内容。
  • Just because byte is theoretically 1 byte doesn't mean it takes just one in memory.
  • 仅仅因为从理论上说,一个字节并不意味着它只需要一个内存。
  • There will be loops in object references, so you'll need to keep a HashMap or somesuch using object-equals as the comparator to eliminate infinite loops.
  • 在对象引用中会有循环,因此您需要使用对象-equals作为消除无限循环的比较器来保存HashMap或somesuch。

@jodonnell: I like the simplicity of your solution, but many objects aren't Serializable (so this would throw an exception), fields can be transient, and objects can override the standard methods.

@jodonnell:我喜欢您的解决方案的简单性,但是许多对象都不是可序列化的(因此这会引发异常),字段可以是临时的,对象可以重写标准方法。

#10


6  

You have to measure it with a tool, or estimate it by hand, and it depends on the JVM you are using.

您必须使用工具来度量它,或者手动估计它,这取决于您使用的JVM。

There is some fixed overhead per object. It's JVM-specific, but I usually estimate 40 bytes. Then you have to look at the members of the class. Object references are 4 (8) bytes in a 32-bit (64-bit) JVM. Primitive types are:

每个对象都有一些固定的开销。它是特定于jvm的,但我通常估计有40个字节。然后你要看看班上的同学。对象引用在32位(64位)JVM中是4(8)字节。基本类型是:

  • boolean and byte: 1 byte
  • 布尔和字节:1字节。
  • char and short: 2 bytes
  • char和short: 2字节。
  • int and float: 4 bytes
  • int和float: 4字节。
  • long and double: 8 bytes
  • long和double: 8字节。

Arrays follow the same rules; that is, it's an object reference so that takes 4 (or 8) bytes in your object, and then its length multiplied by the size of its element.

数组遵循相同的规则;也就是说,它是一个对象引用,在对象中使用4(或8)个字节,然后它的长度乘以它的元素的大小。

Trying to do it programmatically with calls to Runtime.freeMemory() just doesn't give you much accuracy, because of asynchronous calls to the garbage collector, etc. Profiling the heap with -Xrunhprof or other tools will give you the most accurate results.

freememory()只是没有给你太多的准确性,因为对垃圾收集器的异步调用等等。用-Xrunhprof或其他工具对堆进行分析,会得到最准确的结果。

#11


6  

There is also the Memory Measurer tool (formerly at Google Code, now on GitHub), which is simple and published under the commercial-friendly Apache 2.0 license, as discussed in a similar question.

还有一个内存测量工具(以前在谷歌代码中,现在在GitHub上),它很简单,在商业友好的Apache 2.0许可下发布,就像在类似的问题中讨论的一样。

It, too, requires a command-line argument to the java interpreter if you want to measure memory byte consumption, but otherwise seems to work just fine, at least in the scenarios I have used it.

如果您想要测量内存字节的消耗,那么它也需要java解释器的命令行参数,但是在其他情况下,至少在我使用的场景中是这样的。

#12


6  

I recommend the java-sizeof library for carrotsearch. It is very simple.

我推荐用于carrotsearch的java-sizeof库。它是非常简单的。

You can get it in maven:

你可以在maven中得到它:

 <dependency>
    <groupId>com.carrotsearch</groupId>
    <artifactId>java-sizeof</artifactId>
    <version>0.0.3</version>
</dependency>

It is only one code line that return the bytes of an object:

只有一个代码行返回一个对象的字节:

RamUsageEstimator.sizeOf(new Object());

You can see the source code at https://github.com/dweiss/java-sizeof

您可以在https://github.com/dweiss/javasizeof上看到源代码。

And there is a presentation from the author of the library http://www.slideshare.net/DawidWeiss/sizeofobject-how-much-memory-objects-take-on-jvms-and-when-this-may-matter?ref=http://cheremin.blogspot.com/2012/05/how-much-memory-objects-take-on-jvm-and.html

还有一个来自于http://www.slideshare.net/dawidweiss/sizeofobject - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

#13


5  

The java.lang.instrument.Instrumentation class provides a nice way to get the size of a Java Object, but it requires you to define a premain and run your program with a java agent. This is very boring when you do not need any agent and then you have to provide a dummy Jar agent to your application.

java.lang.instrument。工具类提供了一个获得Java对象大小的好方法,但是它要求您定义一个premain并使用Java代理运行您的程序。当您不需要任何代理时,这是非常令人厌烦的,然后您必须为您的应用程序提供一个虚拟的Jar代理。

So I got an alternative solution using the Unsafe class from the sun.misc. So, considering the objects heap alignment according to the processor architecture and calculating the maximum field offset, you can measure the size of a Java Object. In the example below I use an auxiliary class UtilUnsafe to get a reference to the sun.misc.Unsafe object.

因此,我从sun.misc得到了一个使用不安全类的替代解决方案。因此,根据处理器架构和计算最大字段偏移量来考虑对象堆对齐,您可以测量Java对象的大小。在下面的例子中,我使用一个辅助类UtilUnsafe来获取对sun.misc的引用。不安全的对象。

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() { }
}

#14


2  

I wrote a quick test once to estimate on the fly:

我曾写过一次快速测试来估算飞行时间:

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();
    }

}

General concept is allocate objects and measure change in free heap space. The key being getFreeMemory(), which requests GC runs and waits for the reported free heap size to stabilize. The output of the above is:

一般概念是在*堆空间中分配对象和度量变化。关键是getFreeMemory(),它请求GC运行并等待报告的空闲堆大小稳定。上面的输出是:

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

Which is what we expect, given alignment behavior and possible heap block header overhead.

这就是我们所期望的,给定对齐行为和可能的堆块头开销。

The instrumentation method detailed in the accepted answer here the most accurate. The method I described is accurate but only under controlled conditions where no other threads are creating/discarding objects.

该仪器方法详细的在公认的答案这里是最准确的。我描述的方法是准确的,但只有在没有其他线程创建/丢弃对象的受控条件下。

#15


2  

Here is a utility I made using some of the linked examples to handle 32-bit, 64-bit and 64-bit with compressed OOP. It uses sun.misc.Unsafe.

这里是一个实用程序,我使用一些链接的示例来处理32位、64位和64位的压缩OOP。它使用sun.misc.Unsafe。

It uses Unsafe.addressSize() to get the size of a native pointer and Unsafe.arrayIndexScale( Object[].class ) for the size of a Java reference.

它使用Unsafe.addressSize()来获取本机指针的大小和不安全。arrayIndexScale(Object[]。类)用于Java引用的大小。

It uses the field offset of a known class to work out the base size of an object.

它使用已知类的字段偏移量来计算对象的基本大小。

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 );
    }
}

#16


2  

Without having to mess with instrumentation and so on, and if you don't need to know the byte-exact size of an object, you could go with the following approach:

如果你不需要摆弄仪器等等,如果你不需要知道一个物体的字节精确大小,你可以使用下面的方法:

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

do your job here

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

This way you read the used memory before and after, and calling the GC just before getting the used memory you lower the "noise" almost to 0.

通过这种方式,您可以在使用之前和之后读取所使用的内存,并在使用内存之前调用GC,从而将“噪声”降低到几乎为0。

For a more reliable result you can run your job n times, and then divide the used memory by n, obtaining how much memory one run takes. Even more, you can run the whole thing more times and make an average.

为了获得更可靠的结果,您可以运行您的作业n次,然后将使用的内存除以n,获得一次运行所需的内存。更重要的是,你可以把整件事做的更多次,并做出一个平均值。

#17


1  

There isn't a method call, if that's what you're asking for. With a little research, I suppose you could write your own. A particular instance has a fixed sized derived from the number of references and primitive values plus instance bookkeeping data. You would simply walk the object graph. The less varied the row types, the easier.

如果这是你要的,那就没有方法调用。有一点研究,我想你可以自己写。一个特定的实例有一个固定的大小,它来自于引用的数量和原始值加上实例bookkeeping数据。你只需要走物体图。行类型越少,就越容易。

If that's too slow or just more trouble than it's worth, there's always good old-fashioned row counting rule-of-thumbs.

如果这太慢了,或者只是麻烦大于它的价值,那么总是有很好的老式的计数规则。

#18


0  

You could generate a heap dump (with jmap, for example) and then analyze the output to find object sizes. This is an offline solution, but you can examine shallow and deep sizes, etc.

您可以生成堆转储(例如使用jmap),然后分析输出以查找对象大小。这是一个离线的解决方案,但是您可以检查浅层和深度的大小,等等。

#19


0  

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

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

size gives you the increase in memory usage of the jvm due to object creation and that typically is the size of the object.

由于对象的创建,大小会增加jvm的内存使用量,而这通常是对象的大小。

#20


0  

My answer is based on the code supplied by Nick. That code measures total amount of bytes which are occupied by the serialized object. So this actually measures serialization stuff + plain object memory footprint (just serialize for example int and you will see that total amount of serialized bytes is not 4). So if you want to get raw byte number used exactly for your object - you need to modify that code a bit. Like so:

我的回答是基于Nick提供的代码。该代码度量被序列化的对象占用的总字节数。这实际上措施序列化东西+普通对象内存占用(例如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;
    }    

}

I've tested this solution with primitive types, String, and on some trivial classes. There may be not covered cases also.

我已经用基本类型、字符串和一些普通类测试了这个解决方案。也可能没有涵盖的案例。


UPDATE: Example modified to support memory footprint calculation of array objects.

更新:示例修改以支持数组对象的内存占用计算。

#21


0  

This answer is not related to Object size, but when you are using array to accommodate the objects; how much memory size it will allocate for the object.

这个答案与对象大小无关,但是当您使用数组来容纳对象时;它将为对象分配多少内存大小。

So arrays, list, or map all those collection won't be going to store objects really (only at the time of primitives, real object memory size is needed), it will store only references for those objects.

因此,数组、列表或映射所有这些集合不会真正地存储对象(只有在原语的时候,真正的对象内存大小是需要的),它将只存储这些对象的引用。

Now the Used heap memory = sizeOfObj + sizeOfRef (* 4 bytes) in collection

现在,在集合中使用的堆内存= sizeOfObj + sizeOfRef(* 4字节)。

  • (4/8 bytes) depends on (32/64 bit) OS
  • (4/8字节)取决于(32/64位)操作系统。

PRIMITIVES

原语

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.

I mean to say all the object REFERENCE needs only 4 bytes of memory. It may be String reference OR Double object reference, But depends on object creation the memory needed will vary.

我的意思是,所有对象引用只需要4个字节的内存。它可能是字符串引用或双对象引用,但是依赖于对象创建,所需的内存将会有所不同。

e.g) If i create object for the below class ReferenceMemoryTest then 4 + 4 + 4 = 12 bytes of memory will be created. The memory may differ when you are trying to initialize the references.

如果我为下面的类ReferenceMemoryTest创建对象,那么将创建4 + 4 + 4 = 12字节的内存。当您试图初始化引用时,内存可能会有所不同。

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

So when are creating object/reference array, all its contents will be occupied with NULL references. And we know each reference requires 4 bytes.

因此,当创建对象/引用数组时,所有的内容都将被空引用占据。我们知道每个引用需要4个字节。

And finally, memory allocation for the below code is 20 bytes.

最后,下面代码的内存分配是20字节。

ReferenceMemoryTest ref1 = new ReferenceMemoryTest(); ( 4(ref1) + 12 = 16 bytes) ReferenceMemoryTest ref2 = ref1; ( 4(ref2) + 16 = 20 bytes)

参考文献[参考文献];(参考文献4(ref1) + 12 = 16字节)(4(ref2) + 16 = 20字节)

#22


0  

Just use java visual VM.

只需使用java visual VM。

It has everything you need to profile and debug memory problems.

它有所有您需要的配置和调试内存问题。

It also has a OQL (Object Query Language) console which allows you to do many useful things, one of which being sizeof(o)

它还有一个OQL(对象查询语言)控制台,它允许您做许多有用的事情,其中一个是sizeof(o)

#23


-2  

The below code can help you surely.

下面的代码可以帮助您确定。

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

returns size in bytes

返回字节数

I checked it with my JSONArray object by writing it to a file. It is giving object size.

我通过将JSONArray对象写入文件来检查它。它提供对象大小。

#24


-6  

I doubt you want to do it programmatically unless you just want to do it once and store it for future use. It's a costly thing to do. There's no sizeof() operator in Java, and even if there was, it would only count the cost of the references to other objects and the size of the primitives.

我怀疑您是否想要以编程方式完成它,除非您只想做一次并存储它以备将来使用。这是一件昂贵的事情。Java中没有sizeof()操作符,即使有,它也只会计算对其他对象的引用的成本和原语的大小。

One way you could do it is to serialize the thing to a File and look at the size of the file, like this:

一种方法是将该文件序列化为文件,然后查看文件的大小,如下所示:

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

Of course, this assumes that each object is distinct and doesn't contain non-transient references to anything else.

当然,这假定每个对象都是不同的,并且不包含对其他任何东西的非瞬态引用。

Another strategy would be to take each object and examine its members by reflection and add up the sizes (boolean & byte = 1 byte, short & char = 2 bytes, etc.), working your way down the membership hierarchy. But that's tedious and expensive and ends up doing the same thing the serialization strategy would do.

另一个策略是使用每个对象并通过反射检查其成员,并将大小(boolean & byte = 1字节,short & char = 2字节,等等)添加到成员层次结构中。但这很乏味,而且代价高昂,结果就是序列化策略所做的事情。