Cache implementation: when designing the JVM cache (instead of using Memcached or Redis), you need to know whether the cached object will exceed the JVM's maximum heap limit, if a part of the cached data is discarded beyond the corresponding algorithm, such as LRU, to meet the cache JVM parameter settings for subsequent content, it can help determine-how much Xmx needs to be set just for fun1. Memory layout of ObjectsIn a hot spot virtual machine, the layout of objects stored in memory can be divided into three areas: object Header, Instance Data, and Padding ).Ii. Object HeaderThe JVM object header generally occupies two machine codes and 64bit on 32-bit JVM, 64-bit JVM occupies bits, that is, 8 + 8 = 16 bytes (4 + 8 = 12 bytes after enabling pointer compression, the object header of the array object occupies 24 bytes, and 16 bytes after compression is enabled. The reason for occupying more memory than ordinary objects is that extra space is required to store the length of the array.Iii. instance dataThe memory usage of the native type (primitive type) is as follows:
Primitive Type |
Memory Required (bytes) |
Boolean |
1 |
Byte |
1 |
Short |
2 |
Char |
2 |
Int |
4 |
Float |
4 |
Long |
8 |
Double |
8 |
The reference type (Integer) occupies 4 bytes per 32-bit System (namely, 32 bit, to manage 2 ^ 32 = 4 GB memory ), each 64-bit system occupies 8 bytes (4 bytes for enabling compression ).Iv. Alignment FillingThe alignment mode of the hot spot is 8-byte alignment. If the Padding is insufficient, the padding alignment is required. formula: (Object Header + instance data + padding) % 8 = 0 (0 <= Padding <8)5. Calculate the space occupied by Java objectsUse the getObjectSize method of the Instrument interface to calculate the space occupied by objectsSizeOfAgent: large and small computing object class
Package com. wenniuwuren. objectsizeof; 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;/*** use the getObjectSize method of the Instrumentation interface to calculate the space occupied by the object * The original sizeOf can only calculate the space occupied by the object, and cannot calculate the space occupied by the inheritance, * However, we can use the reflection method to calculate all occupied space. ** Created by zhuyb on 16/3/20. */public class SizeOfAgent {static Instrumentation instrumentation; // The first parameter is-javaagent, and the second parameter is passed into public static void premain (String agentArgs, Instrumentation instP) by JVM) {instrumentation = instP;} // returns the public static long sizeOf (Object o) {if (instrumentation = null) Size of an Object without subclass) {throw new IllegalStateException ("Can not access instrumentation environment. \ n "+" Please check if jar file containing SizeOfAgent class is \ n "+" specified in the java's \ "-javaagent \" command line argument. ");} return instrumentation. getObjectSize (o);}/*** calculate the composite object * @ param obj object to calculate size of * @ return Object size */public static long fullSizeOf (object obj) {Map
Visited = new IdentityHashMap
(); Stack
Stack = new Stack(); Long result = internalSizeOf (obj, stack, visited); while (! Stack. isEmpty () {result + = internalSizeOf (stack. pop (), stack, visited);} visited. clear (); return result;} // This algorithm allows each Object to be calculated only once to avoid circular reference. That is, the private static boolean skipObject (Object obj, Map
Visited) {if (obj instanceof String) {// if (obj = (String) obj) is no longer calculated in the String pool ). intern () {return true ;}} return (obj = null) // The existing object is no longer calculated. | visited. containsKey (obj);} private static long internalSizeOf (Object obj, Stack
Stack, Map
Visited) {if (skipObject (obj, visited) {return 0;} visited. put (obj, null); long result = 0; // get size of object + primitive variables + member pointers result + = SizeOfAgent. sizeOf (obj); // process all array content Class clazz = obj. getClass (); if (clazz. isArray () {// [I, [F basic type name length is 2 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 ;}// process all the fields of the object while (clazz! = Null) {Field [] fields = clazz. getDeclaredFields (); for (int I = 0; I <fields. length; I ++) {// if (! Modifier. isStatic (fields [I]. getModifiers () {// do not repeat the original type field if (fields [I]. getType (). isPrimitive () {continue;} else {// make the private attribute accessible to fields [I]. setAccessible (true); try {// objects to be estimated are put to stack Object objectToAdd = fields [I]. get (obj); if (objectToAdd! = Null) {stack. add (objectToAdd) ;}} catch (IllegalAccessException ex) {assert false ;}}} clazz = clazz. getSuperclass () ;} return result ;}}
Use the above Code to compress the above code into a jar package, and set the parameters (Premain-Class: sizeof. agent. SizeOfAgentBoot-Class-Path:
Can-Redefine-Classes: false) If Maven is used for packaging, you Can directly set the MANIFEST. MF parameter in pom. xml:
Maven-jar-plugin
2.4
SizeOfAgent
com.wenniuwuren.objectsizeof.SizeOfAgent
false
false
Test class: SizeOfAgentTest
Package com. wenniuwuren. objectsizeof; import static com. wenniuwuren. objectsizeof. sizeOfAgent. *;/*** the following results are tested in 64-bit JVM * startup parameter 1 (no compression of pointer length):-javaagent: target/SizeOfAgent. jar-XX:-UseCompressedOops ** Created by zhuyb on 16/3/20. */public class SizeOfAgentTest {public static void main (String [] args) {System. out. println ("------------------ empty object ----------------------------"); // 16 bytes + 0 + 0 = 16 empty object, only the object header System. out. println ("sizeOf (new Object () =" + sizeOf (new Object (); System. out. println ("fullSizeOf (new Object () =" + fullSizeOf (new Object (); System. out. println ("---------------- the non-null object contains the original type, reference type ----------------------------"); // 16 bytes + 8 + 4 + padding = 32 System. out. println ("sizeOf (new A () =" + sizeOf (new A (); System. out. println ("fullSizeOf (new A () =" + fullSizeOf (new A (); // 16 + 4 + padding = 24 data is an int System. out. println ("sizeOf (new Integer (1) =" + sizeOf (new Integer (1); // (16 + int hash: 4 + int hash32: 4 + refer char value []: 8 + padding) = 32 // static attributes (static) do not calculate space, because all objects share a space. // different JDK versions may have different internal fields in the String. JDK1.7 System is used in this test. out. println ("sizeOf (new String () =" + sizeOf (new String (); // (16 + 4 + 4 + 8 + padding) + (24 + 0 + padding) = 56 System. out. println ("fullSizeOf (new String () =" + fullSizeOf (new String (); // (16 + 4 + 4 + 8 + padding) = 32 System. out. println ("sizeOf (new String ('A') =" + sizeOf (new String (""))); // (16 + 4 + 4 + 8 + padding) + (24 + 2 + padding) = 64 System. out. println ("fullSizeOf (new String ('A') =" + fullSizeOf (new String ("a"); System. out. println ("------------------- original type array object -------------------------"); // 24 bytes + 0*1 + 0 = 24 array length is 0, so only the length of the object header is System. out. println ("sizeOf (new byte [0]) =" + sizeOf (new byte [0]); System. out. println ("fullSizeOf (new byte [0]) =" + fullSizeOf (new byte [0]); // 24 + 1*1 + padding = 32 System. out. println ("sizeOf (new byte [1]) =" + sizeOf (new byte [1]); System. out. println ("fullSizeOf (new byte [1]) =" + fullSizeOf (new byte [1]); // 24 + 1*2 + padding = 32 System. out. println ("sizeOf (new char [1]) =" + sizeOf (new char [1]); System. out. println ("fullSizeOf (new char [1]) =" + fullSizeOf (new char [1]); // 24 + 9*1 + padding = 40 System. out. println ("sizeOf (new byte [9]) =" + sizeOf (new byte [9]); System. out. println ("fullSizeOf (new byte [9]) =" + fullSizeOf (new byte [9]); System. out. println ("-------------------- reference type array object ------------------------"); // 24 bytes + 0*8 + 0 = 24 the array length is 0 System. out. println ("sizeOf (new Integer [0]) =" + sizeOf (new Integer [0]); System. out. println ("fullSizeOf (new Integer [0]) =" + fullSizeOf (new Integer [0]); // 24 bytes + 1*8 + 0 = 32 reference object 64-bit JVM occupies 8 bytes System. out. println ("sizeOf (new Integer [1]) =" + sizeOf (new Integer [1]); System. out. println ("fullSizeOf (new Integer [1]) =" + fullSizeOf (new Integer [1]); // 24 bytes + 2*8 + padding = 40 System. out. println ("sizeOf (new Integer [1]) =" + sizeOf (new Integer [1]); System. out. println ("fullSizeOf (new Integer [1]) =" + fullSizeOf (new Integer [1]); // 24 + 3*8 + padding = 48 System. out. println ("sizeOf (new Integer [3]) =" + sizeOf (new Integer [3]); System. out. println ("fullSizeOf (new Integer [3]) =" + fullSizeOf (new Integer [3]); System. out. println ("------------------- custom array object -------------------------"); // 16 + (4 + 8) + padding = 32 System. out. println ("sizeOf (new B () =" + sizeOf (new B (); System. out. println ("fullSizeOf (new B () =" + fullSizeOf (new B ())); // 24 + 0*8 + padding = 24 reference object 64-bit JVM occupies 8 bytes, // because no real new B () is created () so Class B internal data does not occupy space System. out. println ("sizeOf (new B [0]) =" + sizeOf (new B [0]); System. out. println ("fullSizeOf (new B [0]) =" + fullSizeOf (new B [0]); // 24 + 1*8 + padding = 32 System. out. println ("sizeOf (new B [1]) =" + sizeOf (new B [1]); System. out. println ("fullSizeOf (new B [1]) =" + fullSizeOf (new B [1]); // 24 + 2*8 + padding = 40 System. out. println ("sizeOf (new B [2]) =" + sizeOf (new B [2]); System. out. println ("fullSizeOf (new B [2]) =" + fullSizeOf (new B [2]); // 24 + 3*8 + padding = 48 System. out. println ("sizeOf (new B [3]) =" + sizeOf (new B [3]); System. out. println ("fullSizeOf (new B [3]) =" + fullSizeOf (new B [3]); System. out. println ("------------------- composite object -------------------------"); // 16 + (4 + 8) + padding = 32 sizeOf only calculates the space occupied by a single layer. System. out. println ("sizeOf (new C () =" + sizeOf (new C (); // (16 + (4 + 8) + padding1) + (24 + 2*8 + padding2) + 2*(16 + (4 + 8) + padding3) = 136 // recursively calculates the total space occupied by the current object, including the size of the current class and super class instance fields and the size of the Instance field reference object System. out. println ("fullSizeOf (new C () =" + fullSizeOf (new C (); System. out. println ("------------------- inheritance relationship -------------------------"); // when an inheritance relationship is involved, there is a basic rule: first, store the members in the parent class, and then the members in the subclass, the parent class must also follow the 8 byte rules/16 + 1 + padding = 24 System. out. println ("sizeOf (new D () =" + sizeOf (new D (); System. out. println ("fullSizeOf (new D () =" + fullSizeOf (new D (); // 16 + parent class (1 + padding1) + 1 + padding2 = 32 System. out. println ("sizeOf (new E () =" + sizeOf (new E (); System. out. println ("fullSizeOf (new E () =" + fullSizeOf (new E ();} public static class A {int a; Integer B ;} public static class B {int a; Integer B;} public static class C {int c; B [] B = new B [2]; // initialize C () {for (int I = 0; I <B. length; I ++) {B [I] = new B () ;}} public static class D {byte d1 ;} public static class E extends D {byte e1 ;}}
Run:If the JVM parameter-javaagent: target/SizeOfAgent needs to be set when the IDE is running. jar-XX:-UseCompressedOops; if you run the following command on the command line: java-javaagent: sizeofag. jar-XX:-UseCompressedOops main class name. Test results:
------------------ Empty Object -------------------------- sizeOf (new Object () = 16 fullSizeOf (new Object () = 16 ---------------- non-empty Object contains original type, reference type ------------------------------ sizeOf (new ()) = 32 fullSizeOf (new A () = 32 sizeOf (new Integer (1) = 24 sizeOf (new String () = 32 fullSizeOf (new String ()) = 56 sizeOf (new String ('A') = 32 fullSizeOf (new String ('A') = 64 --------------------- original type array object --------------------------- sizeOf (new byte [0]) = 24 fullSizeOf (new byte [0]) = 24 sizeOf (new byte [1]) = 32 fullSizeOf (new byte [1]) = 32 sizeOf (new char [1]) = 32 fullSizeOf (new char [1]) = 32 sizeOf (new byte [9]) = 40 fullSizeOf (new byte [9]) = 40 -------------------- reference type array object -------------------------- sizeOf (new Integer [0]) = 24 fullSizeOf (new Integer [0]) = 24 sizeOf (new Integer [1]) = 32 fullSizeOf (new Integer [1]) = 32 sizeOf (new Integer [1]) = 32 fullSizeOf (new Integer [1]) = 32 sizeOf (new Integer [3]) = 48 fullSizeOf (new Integer [3]) = 48 ------------------- custom array object ----------------------------- sizeOf (new B () = 32 fullSizeOf (new B ()) = 32 sizeOf (new B [0]) = 24 fullSizeOf (new B [0]) = 24 sizeOf (new B [1]) = 32 fullSizeOf (new B [1]) = 32 sizeOf (new B [2]) = 40 fullSizeOf (new B [2]) = 40 sizeOf (new B [3]) = 48 fullSizeOf (new B [3]) = 48 ------------------- composite object ----------------------- sizeOf (new C () = 48 fullSizeOf (new C () = 152 ------------------- inheritance relation --------------------------- sizeOf (new D ()) = 24 fullSizeOf (new D () = 24 sizeOf (new E () = 32 fullSizeOf (new E () = 32
The Calculation of composite objects in the test class may be cumbersome. You can see clearly the space occupied by new C:
Vi. SummaryThe overall Java object is implemented according to certain rules. By clarifying the memory layout and allocation rules of JVM objects, it is easier to calculate the size of Java objects. Java does not provide the object size like C ++. This is the original design intention of the Java language (Automatic Memory Management). However, with the in-depth understanding of Java, the underlying implementation of JVM (implemented using C and C ++) has become another issue. The reference in this article was in 2007 and has been available for nine years. The reference content is still valid so far. JVM-related things are indeed quite small and interesting.