How to accurately measure the size of Java objects

Source: Internet
Author: User

About the size of the Java object Measurement, there are many examples online, most of the application of an object after the start of GC, after comparison of the size, but so, although it is possible to say that the size of the measured object is feasible, but not necessarily completely accurate, 因为过程中包含对象本身的开销 maybe you lucky, just can meet, almost, But this kind of test often seems very cumbersome, because to write a bunch of code to test a little bit of things, and only in the local test play, to really test the actual system object size so that can not, this article said Java some relatively low-level knowledge, how to measure object size, Java is actually a way to provide. Note: 本文的内容仅仅针对于Hotspot VM If you don't know how to measure the size of the JVM's objects before, and you want to know, follow me one step at a time and you'll understand.

First, we first write a piece of code that you might not write or think is impossible: a class, several types are private types, there is no public method, how to read and write these properties, it seems impossible oh, why, this violates the object-oriented encapsulation, in fact, when necessary, Leaving a back door can make the language more productive, the serialization of the object will not be saved because there is no public method can not save success, OK, we simply write a paragraph code, gradually introduced to how to test the size of the object, the code is very simple, I believe I do not explain what:

Import Java.lang.reflect.Field;  Class NodeTest1 {        private int a =;      private int b = +;  } public class Test001 {public        static void main (String []args) {          NodeTest1 node = new NodeTest1 ();          Field []fields = NodeTest1.class.getDeclaredFields ();          for (Field field:fields) {              field.setaccessible (true);              try {                  int i = field.getint (node);                  Field.setint (node, I * 2);                  System.out.println (Field.getint (node));              } catch (IllegalArgumentException e) {                  e.printstacktrace ();              } catch (Illegalaccessexception e) {                  E.printstacktrace ();}}}  

The most basic meaning of the code is: Instantiate an instance of the class NodeTest1, and then take out two properties, multiplied by 2, and then output, I believe you will think this how possible, NodeTest1 there is no public method, the code is here, the code will be copied back to run OK, OK, now don't say this, the result is:

26
42

Why can be taken, is that each attribute has left a door, mainly for their own or external access convenience, I believe that the code of their own careful friend, should know that the door is in: The field.setAccessible(true); access to represent the domain is opened, like a backdoor opened, hehe, the above method if not set this, the direct error.

It seems to have nothing to do with the size of the object, but this is only a hint, because we first have to get the object's properties, we can know the size of the object, 对象如果没有提供public方法我们也要知道它有哪些属性 so we will probably use this similar code later Oh!

The key to measuring the size of an object is Java-provided (only after 1.5): java.lang.instrument.Instrumentation It provides a rich API for tracking and measuring the size of the object (this article only describes the size of the object), so I am happy, but the more disgusting is that it is an instantiation class: sun.instrument.IntrumentationImpl是sun开头的,这个鬼东西有点不好搞,翻开源码构造方法是private类型,没有任何getInstance的方法 , why do you write this class? It seems that this can only be initialized by the JVM itself, then how to take its own initialization of things to use it, 唯一能想到的就是agent代理 then we first put aside the agent, first to write a simple object measurement method:

步骤1: (Create a processing class to test the object size first)

import java.lang.instrument.Instrumentation;          public class Mysizeof {private static instrumentation inst;  /** * This method must be written and will be enabled on agent invocation */public static void Premain (String Agentargs, Instrumentation INSTP)          {inst = INSTP;  }//is used to measure the size of the Java object (here first understand that the size is correct, and then deepen) public static long SizeOf (object o) {if (inst = = null)                      {throw new IllegalStateException ("Can not access instrumentation environment.\n" + "Please check if jar file containing Sizeofagent class is \ n" + "specified in the Java ' s \"-javaagen            T\ "command line argument.");          return Inst.getobjectsize (o); }}

步骤2: Above we have written the agent's code, at this time we want to 将上面这个类编译后打包为一个jar文件 , and on its 包内部的META-INF/MANIFEST.MF文件中增加一行:Premain-Class: MySizeOf behalf to execute the full name of the agent, where the class name is no package, if you have a package, then write the full name, we assume that the packaged jar package name is Agent.jar (The packaging process here is a simple elaboration, do not elaborate), OK, continue to go down:

步骤3: Write test class, write in test class:

public class Testsize {public          static void main (String []args) {              System.out.println (mysizeof.sizeof (New Integer (1)));              System.out.println (mysizeof.sizeof (New String ("a"));              System.out.println (mysizeof.sizeof (new char[1]));}          }

The next step is ready to run, before the run we are ready to estimate what the results are, and I am currently running the JVM in 32bit mode (note that the JVM parameter settings for different bits are not the same and the object size is not as large).

(1) First look at the integer object, in 32bit mode, theclass area occupies 4byte,the mark area occupies a minimum of 4byte, so the minimum 8byte head, integer internal has an int type of data, accounting for 4 bytes, So at this time for 8+4=12,java default requirements according to 8byte object to it, so to 16byte, so we theoretical results first should be 16;
(2) Look at string, the length of the 1,string object itself has 4 non-static properties (static property We do not calculate space, because all objects are shared a piece of space), 4 non-static properties, there is offset, count, hash is an int type, Occupy 4 Byte,char value[] As a pointer, the size of the pointer in bit mode or 64bit to turn on the pointer compression default is 4byte, so the property occupies the 16byte,string itself has 8byte head, so occupy the 24byte; A string containing a sub-object char array, the difference between an array object and a normal object is the need to use a field to save the length of the array, so the head becomes 12byte,java in a char with UTF-16 encoding, occupies 2 byte, so it is 14byte, to the 16byte,24+16=40byte;
(3) The third one on the second basis has been analyzed, is 16byte size;

That is, the theoretical results are: 16, 40, 16;

步骤4: Start running code now: Before running the code, you need to make sure that classpath contains the Agent.jar just now:

D:>javac Testsize.java
D:>java-javaagent:agent.jar testsize
16
24
16

The first and third results agree, but strange, how the second is 24, not 40, how to deviate from the theoretical results so large, and then back to the theoretical results, there is a 24 once appeared, 24 refers to the string without the space size of the char array, then this is really true, visible, Java By default provides methods to measure the object's current size only , if you want to measure the actual size of the object (that is, the child object is included, then you need to write the algorithm to calculate, the simplest way is recursive, but recursive one is I do not like to use the , accidentally in a place to see someone with a stack of write a code to write well, himself slightly changed, that is the following.

Import java.lang.instrument.Instrumentation;  Import Java.lang.reflect.Array;  Import Java.lang.reflect.Field;  Import Java.lang.reflect.Modifier;  Import Java.util.IdentityHashMap;  Import Java.util.Map;  Import Java.util.Stack;      public class Mysizeof {static Instrumentation inst;      public static void Premain (String Agentargs, instrumentation instp) {inst = INSTP; } public static Long SizeOf (Object o) {if (inst = = null) {throw new IllegalStateException ("Can No               T access instrumentation environment.\n "+" Please check if the jar file containing Sizeofagent class is \ n "+         "Specified in the Java's \"-javaagent\ "command line argument.");      return Inst.getobjectsize (o); } public static long Fullsizeof (object obj) {//Deep retrieve object, and calculate size Map<object, object> visited = new Identityh         Ashmap<object, object> ();         stack<object> stack = new stack<object> (); Long ResUlt = internalsizeof (obj, stack, visited);         while (!stack.isempty ()) {//traversal through stack result + = internalsizeof (Stack.pop (), stack, visited);         } visited.clear ();      return result; }//Determine which private static Boolean skipobject (Object obj, Map<object, object> visited) {if (OB) that need to be skipped            J instanceof String) {if (obj = = ((String) obj). Intern ()) {return true; }} return (obj = = null) | |      Visited.containskey (obj);         } private static Long internalsizeof (Object obj, stack<object> Stack, Map<object, Object> visited) {         if (Skipobject (obj, visited)) {//skips the constant pool object, skips the object that has already been accessed, return 0;         } visited.put (obj, null);//Put the current object on the stack long result = 0;         Result + = SizeOf (obj);         Class <?>clazz = Obj.getclass ();         if (Clazz.isarray ()) {//if array if (Clazz.getname (). Length ()! = 2) {//Skip primitive type array       int length = array.getlength (obj);                for (int i = 0; i < length; i++) {Stack.add (Array.get (obj, i));         }} return result;     } return Getnodesize (Clazz, result, obj, stack);  }//This method gets the size of the non-array object itself and can be searched up to the parent class private static long Getnodesize (class <?>clazz, long result, object obj            , stack<object> Stack) {while (clazz! = null) {field[] fields = Clazz.getdeclaredfields (); for (Field field:fields) {if (! Modifier.isstatic (Field.getmodifiers ())) {//here throw away the static property if (Field.gettype (). Isprimitive ()) {//This throws away the basic keywords (because                     For the basic keyword in the call Java default method provided by the already computed) continue;                        }else {field.setaccessible (true);                             try {Object objecttoadd = field.get (obj);              if (objecttoadd! = null) {                      Stack.add (Objecttoadd);//Put the object on the stack and continue retrieving it after the popup} C                    Atch (Illegalaccessexception ex) {assert false;    }}}} Clazz = Clazz.getsuperclass ();//Find the parent class until there is no parent class} return result; }  }

To modify a test class:

public class Testsize {public   static void main (String []args) {     System.out.println (mysizeof.sizeof (New Integer (1)));     System.out.println (mysizeof.sizeof (New String ("a"));     System.out.println (mysizeof.fullsizeof (New String ("a"));     System.out.println (mysizeof.sizeof (new char[1]));   }

D:>javac Testsize.java
D:>java-javaagent:agent.jar testsize
16
24
40
16

This result is what we want, it seems that the test is reliable, in the face of theory and test results, as well as the above so-called alignment method, you can write some of their own classes of objects to test the size and actual consistency;

最后,文章补充一些:

    1. The object is 8-byte aligned in the same way whether 32bit or 64bit is the same;
    2. Java in 64bit mode to open pointer compression, than 32bit mode, the head will be large 4byte (Mark area to 8byte, theclass area is compressed), if the pointer compression is not turned on, the head will be large 8byte (_mark and _ Class will become 8byte), jdk1.6 introduced the parameter-xx:+usecompressedoops, in 32G memory the default will automatically open this parameter, as follows:

      [Email protected] ~]$ java-xmx31g-xx:+printflagsfinal |grep Compress
      BOOL Specialstringcompress = true {product}
      BOOL Usecompressedoops: = True {lp64_product}
      BOOL Usecompressedstrings = false {product}
      [Email protected] ~]$ java-xmx32g-xx:+printflagsfinal |grep Compress
      BOOL Specialstringcompress = true {product}
      BOOL Usecompressedoops = false {lp64_product}
      BOOL Usecompressedstrings = false {product}

A simple calculation, in the case of pointer compression, a new String ("a"), the space size of this object is: 12 bytes Head +4*4 = 28 bytes aligned to 32 bytes, and then C points to a char array header more than a normal object 4 byte to hold the length, 12+4+ 2byte character = 16, that is, 48 byte, in fact, even if you new String () will occupy such a large space, because there is alignment, if the length of the character is 8, then it is 12+4+16=32, that is, 64byte;

If you do not turn on pointer compression then calculate: Head becomes 16byte + 4*3 int data + 8 (one pointer) = 36 aligned to 40byte, corresponding char array head becomes 16+4 + 2 = 22 aligned to 24byte,40+24= 64, that is, only one character or 0 characters will be aligned to 64byte, so, you know, how to adjust the parameters, how to write the code, if the length is 8 characters, then the back part will become 16+4+16=36 aligned to 40byte,40+40=80byte, that is, Throw aside other reference spaces (for example, by an array or collection class reference), if you have 10 or so strings, each size is 8 characters, there will be 1 K size, how much in your code? Oh!

These are not what I said, these are a calculation method, and this calculation results will only be less, because the code in the process, the head of some objects will be stretched, the _mark area will not be used outside the space to store, so the official instructions are also, the minimum number of bytes occupied, never say that only the number of bytes.

OK, say very scary, but write code or not afraid, but in these terms, just explain how Java is wasted space, do not blindly use some advanced things, when necessary, consider performance or there is a lot of space, similar to the collection class and multidimensional array, the previous reference is actually not related to the data, But the space occupied is much larger than the data itself.

How to accurately measure the size of Java objects

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.