Java Internals -memory Layout- Part 2

Joe

Thành viên VIP
21/1/13
2,935
1,299
113
This is JAVA Internals Part II. As I introduced the JAVA Internals (Part I) to you I believe that some of you are still not aware about the Memory Structure of JAVA Objects. It's time to dig deeper into JAVA Object Memory Structure. The reason is simple: complex Memory Structure always leads to bad performance and sluggish response time. The more you know about the Memory Structure of JAVA objects the more you make the better choice. And the byproducts are the good performance and the swift response time. Your boss and your customers would be very happy and admire you -the great Data Engineering Guru.

Let review Part I. Fig. 1 shows you the generic Memory Structure of JAVA Object.


Fig.1

To calculate the size of a JAVA object I have showed you the SizeOf API and how it could be implemented. The trade-off is the mandatory use of JVM switch -javaagent:sizeof.jar. Further, the JAVA standard Instrumentation API just returns the shell of an object, not the real size with instantiated and initialized global objects during the runtime. And that is a bit too perfunctory. An inchoate API if you so will.

The insight knowledge of Java Object Structure helps you to optimize the data structure (Data Engineering) and to improve the accesses (Data Mining). Using an existing black-boxed package of the 3rd party is in my opinion an adventure into the Unknown. A real developer always tries first before he starts to scavenge the Web for some ready-for-use package. I'm never against GitHub, but one should be careful with the posted tools. Some are awful and awkward, some are ingenious. A hodgepodge of all the best and all the worst.

The real challenge is to calculate the object size during the runtime at anytime and anywhere. Because JAVA objects are usually started either as null or as instantiated and are changed dynamically their size during the processing phase (increase/decrease as, for example, in an ArrayList). A good Data Engineer or Data Miner is always aware about this dynamicism in order to tailor the reserving size of the memory (heap/stack) optimally.


Dynamic Implementation

Fig.1 shows you a generic JAVA object which contains fields (primitives or other JAVA objects) and these fields will be populated during the runtime. The size changes, but Instrumentation method getObjectSize(Object obj) just returns the same size as if the object wasn't in use. Very confusing and inconvenient. To overcome the obstacles I show you how to implement the generic size calculation of JAVA Object using java.lang.reflect package:
  • Class: to determine the object
  • Field: to extract the using global objects
  • Modifier: to separate static fields from the NON-static
  • etc.
The segregation of static and non-static fields is therefore meaningful because the static fields "belong" to JVM and could be shared by other objects. In other words: they don't really belong the the calculated object.

The size calculation differs from standpoint to standpoint, from view to view. Instrumentation method getObjectSize() is one of the standpoints. It ignores the references (used by object's methods) and therewith the size became somehow imprecise (see Fig.2).


Fig.2 (Source www.programcreek.com)

JAVA array is an object which differs a bit from other JAVA objects. It's a block of 16 bytes (header, length, reference or pointer), some elements-area (EA). The area could be another array block (multi-dimensional array). If there are more Eas than one getObjectSize() simply ignores them as if they didn't exist and only gives back the size of 16-bytes + the size of all elements (see Fig.3)


Fig. 3

The Implementation of Memory Structure and size

The following API Mem.java covers most of the JAVA objects. However, it wasn't thoroughly tested. Undetected Bugs could exist. If you use this API and detect some of them you could report them HERE (Congdongjava.com) and If I have time I'll check, improve or correct them. The source is free. However you have to mention the author when you use it within your app.

Note: If array of more than TWO dimensions the size is depending on the way how the array was initialized. There are two ways to initialize a multiple-dimensional array:
  • Regular: if the dimensions of an array are known it's a regular array. For example: int[][][] a3d = new int[10][5][30].
  • Irregular: if up dimension 2 of an array is unknown it's an irregular array. For example: int[][][] a3d = new int[10][ ] or new int[10][5][ ] whereas the unknown dimensions are usually initialized during the runtime.
In such an Irregular case the calculated array size is imprecise (see example 3: Test3D.java)

The API

API Mem.java consists of two static methods:
  • sizeOf(Object obj) returns the size of the given JAVA object (long value)
  • structureOf(Object obj) returns the size in detailed form (string)
and is highly recursive.

PHP:
import java.util.*;
import java.lang.reflect.*;
// Joe Nartca (C)
public class Mem {
  public static long sizeOf(Object obj) {
	Class<?> cls = obj.getClass();
	if (cls.isArray()) {
	  long size = arraySize(obj);
	  int p = padding(size);
	  return (p > 0)? size+p : size;
	}
	long size = 8;
	List<Object> Ob = new ArrayList<>();
	List<Object> ob = new ArrayList<>();
	List<String> St = new ArrayList<>();
	List<String> st = new ArrayList<>();
	Field[] fs = cls.getDeclaredFields();
	for (Field f : fs) if (!Modifier.isStatic(f.getModifiers())) {
	  Object o = null;
	  try {
		o = f.get(obj);
	  } catch (Exception ex) { }
	  String s = f.getGenericType().getTypeName();
	  if (s.indexOf(".") > 0) {
		St.add(s);
		Ob.add(o);
	  } else {
		st.add(s);
		ob.add(o);
	  }
	}
	size += getField(ob, st, "long", 8);
	size += getField(ob, st, "double", 8);
	size += getField(ob, st, "float", 4);
	size += getField(ob, st, "int", 4);
	size += getField(ob, st, "short", 2);
	size += getField(ob, st, "char", 2);
	size += getField(ob, st, "byte", 1);
	size += getField(ob, st, "boolean", 1);
	size += padding(size);
	// Checking References
	for (int i = 0, mx = St.size(); i < mx; ++i) {
	  Object o = Ob.get(i);
	  if (o != null) { // instantiated object
		if (o.toString().indexOf("@") > 0) size += 4 + sizeOf(o);	  
		else if (St.get(i).lastIndexOf("String") > 0) size += 4 + ((String)o).length();
	  }
	}
	size += padding(size);
	size += getField(ob, st, "[", 4);
	size += padding(size);
 
	// Java Object as field variable
	String CLS = cls.getName();
	CLS = CLS.substring(CLS.lastIndexOf(".")+1);
	if (obj instanceof Collection) { // Collection Objects
	  Collection<?> cObj = (Collection) obj;
	  int len = cObj.size();
	  if (len > 0) { // References
		size += len*4+padding(size);
		Iterator<?> it = cObj.iterator();
		while (it.hasNext()) size += sizeOf(it.next().getClass());
	  }
	} else if (obj instanceof Map) { // Map Objects
	  Map<?, ?> mObj = (Map) obj;
	  int len = mObj.size();
	  if (len > 0) { // Reference
		size += len*4+padding(size);
		Iterator<?> it = mObj.entrySet().iterator();
		while (it.hasNext()) {
		  Map.Entry<?, ?> me = (Map.Entry)it.next();
		  size += sizeOf(me.getKey());
		  size += sizeOf(me.getValue());
		}
	  }
	}
	return size;
  }
  // String.format("% 7d", x): 7 digits with leading blanks for x
  public static String structureOf(Object obj) {
	Class<?> cls = obj.getClass();
	String CLS = cls.getName();
	String T = CLS.substring(CLS.lastIndexOf(".")+1);
	StringBuilder sb = new StringBuilder("MemoryStructureOf: ");
	if (cls.isArray()) {
	  int len = CLS.length();
	  StringBuilder ar = new StringBuilder();
	  if (CLS.indexOf("[J") >= 0)	  ar.append("long");
	  else if (CLS.indexOf("[D") >= 0) ar.append("double");
	  else if (CLS.indexOf("[I") >= 0) ar.append("int");
	  else if (CLS.indexOf("[F") >= 0) ar.append("float");
	  else if (CLS.indexOf("[S") >= 0) ar.append("short");
	  else if (CLS.indexOf("[C") >= 0) ar.append("char");
	  else if (CLS.indexOf("[B") >= 0) ar.append("byte");
	  else if (CLS.indexOf("[Z") >= 0) ar.append("boolean");
	  else if (CLS.indexOf("[L") >= 0) ar.append(T.substring(0, T.length()-1));
   
	  Object o = obj;
	  for (int i = 0, d = 1+obj.toString().lastIndexOf("["); i < d; ++i) {
		if (o != null) {
		  try {
			ar.append("["+Array.getLength(o)+"]");
		  } catch (Exception ex) {
			ar.append("[]");
		  }
		  o = Array.get(o, 0);
		} else ar.append("[]");
	  }
	  String AR = ar.toString();
	  sb.append(AR+ls+
				"	  8: Header"+ls+
				"	  4: Length"+ls+
				"	  4: Reference"+ls);
	  long size = 0;
	  String S = obj.toString();
	  if (S.charAt(1) != '[') {
		len = Array.getLength(obj);
		if (len > 0) {
		  if (S.charAt(1) != 'L') {
			int f = factor(obj.toString());
			int l = f * len;
			sb.append(String.format("% 7d",l)+": "+toPrimitive(S)+"["+len+"]"+ls);
			size = l+16;
		  } else { // Array of Objects
			long L = 0;	   
			if (S.indexOf(".String") > 0) {
			  for (int i = 0; i < len; ++i) L += ((String)Array.get(obj, i)).length();
			  sb.append(String.format("% 7d",L+len*4)+": String["+len+"]"+ls);
			} else {
			  for (int i = 0; i < len; ++i) {
				o = Array.get(obj, i);
				if (o != null) L += sizeOf(o);
			  }
			  sb.append(String.format("% 7d",L+len*4)+": "+
						AR.substring(0,AR.length()-1)+len+"]"+ls);
			}
			size = 16+L+len*4;
		  }
		}
	  } else {
		long L = arraySize(obj);
		sb.append(String.format(String.format("% 7d", L-16))+": "+AR+ls);
		size = L;
	  }
	  int p = padding(size);
	  if (p > 0) {
		size += p;
		sb.append(String.format("% 7d",p)+": Padding"+ls);
	  }
	  sb.append(String.format("% 7d",size)+": Total in bytes"+ls);
	  return sb.toString();
	}
	long size = 8;
	List<Object> Ob = new ArrayList<>();
	List<Object> ob = new ArrayList<>();
	List<String> St = new ArrayList<>();
	List<String> st = new ArrayList<>();
	sb.append(T+ls+"	  8: Header"+ls);
	Field[] fs = cls.getDeclaredFields();
	for (Field f : fs) if (!Modifier.isStatic(f.getModifiers())) {
	  Object o = null;
	  try {
		o = f.get(obj);
	  } catch (Exception ex) { }
	  String s = f.getGenericType().getTypeName();
	  if (s.indexOf(".") > 0) {
		St.add(s);
		Ob.add(o);
	  } else {
		st.add(s);
		ob.add(o);
	  }
	}
	size += getField(sb, ob, st, "long", 8);
	size += getField(sb, ob, st, "double", 8);
	size += getField(sb, ob, st, "float", 4);
	size += getField(sb, ob, st, "int", 4);
	size += getField(sb, ob, st, "short", 2);
	size += getField(sb, ob, st, "char", 2);
	size += getField(sb, ob, st, "byte", 1);
	size += getField(sb, ob, st, "boolean", 1);
 
	int p = padding(size);
	if (p > 0) sb.append(String.format("% 7d",p)+": Padding"+ls);
	size += p;
	// Checking References
	for (int i = 0, mx = St.size(); i < mx; ++i) {
	  long s = 0;
	  Object o = Ob.get(i);
	  String S = St.get(i);
	  if (o != null) { // instantiated object
		if (o.toString().indexOf("@") > 0) {
		  s = 4 + sizeOf(o);
		  sb.append(String.format("% 7d",s)+": "+S+ls);
		} else if (S.lastIndexOf("String") > 0) {
		  s = 4 + ((String)o).length();
		  sb.append(String.format("% 7d",s)+": String"+ls);
		}
	  } else sb.append("   null: "+S.substring(S.lastIndexOf(".")+1)+ls);
	  size += s;
	}
	p = padding(size);
	if (p > 0) sb.append(String.format("% 7d",p)+": Padding"+ls);
	size += p;
 
	size += getField(sb, ob, st, "[", 4);
	p = padding(size);
	if (p > 0) sb.append(String.format("% 7d",p)+": Padding"+ls);
	size += p;
	// Java Object as field variable
	if (obj instanceof Collection) { // Collection Objects
	  Collection<?> cObj = (Collection) obj;
	  int len = cObj.size();
	  if (len > 0) {
		long l = 0;
		String S = null;
		size += 4*len; // Reference
		p = padding(size);
		if (p > 0) sb.append(String.format("% 7d",p)+": Padding"+ls);
		Iterator<?> it = cObj.iterator();
		for (int i = 0; it.hasNext(); ++i) {
		  Object O = it.next();
		  l += sizeOf(O);
		  if (S == null) {
			S = O.getClass().toString();
			S = S.substring(S.lastIndexOf(".")+1);
		  }
		}
		size += l;
		sb.append(String.format("% 7d",l+len*4)+": "+(len*4)+
				  " elements of "+T+"<"+S+">"+ls);
	  }
	} else if (obj instanceof Map) { // Map Objects
	  Map<?, ?> mObj = (Map) obj;
	  int len = mObj.size();
	  if (len > 0) {
		long l = 0;
		size += 4*len;
		p = padding(size);
		String k = null, v = null;
		if (p > 0) sb.append(String.format("% 7d",p)+": Padding"+ls);
		Iterator<?> it = mObj.entrySet().iterator();
		for (int i = 0; it.hasNext(); ++i) {
		  Map.Entry<?, ?> me = (Map.Entry)it.next();
		  Object K = me.getKey();
		  Object V = me.getValue();
		  if (k == null) {
			k = K.getClass().toString();
			k = k.substring(k.lastIndexOf(".")+1);
		  }
		  if (v == null) {
			v = V.getClass().toString();
			v = v.substring(v.lastIndexOf(".")+1);
		  }
		  l += sizeOf(K)+sizeOf(V);
		}
		size += l;
		sb.append(String.format("% 7d",l+len*4)+": "+(len*4)+
				  " elements of "+T+"<"+k+","+v+">"+ls);
	  }
	} // user object
	sb.append(String.format("% 7d",size)+": Total in bytes"+ls);
	return sb.toString();
  }
  private static long arraySize(Object obj) {
	long size = 16;
	if (obj == null) return size;
	int len = Array.getLength(obj);
	if (len == 0) return size;
	String S = obj.toString();
	if (S.charAt(1) == '[') { // next dimension?
	  for (int i = 0; i < len; ++i) size += arraySize(Array.get(obj, i));
	  return size;
	}
	if (S.charAt(1) != 'L') {
	  size += factor(S) * len;
	} else { // Array of Objects
	  size += len*4; // references		
	  if (S.indexOf(".String") > 0) {
		for (int i = 0; i < len; ++i) size += ((String)Array.get(obj, i)).length();
	  } else {
		for (int i = 0; i < len; ++i) {
		  Object o = Array.get(obj, i);
		  if (o != null) size += sizeOf(o);
		}
	  }
	}
	return size;
  }
  private static long getField(List<Object> typ, List<String> st, String s, int f) {
	long size = 0;
	for (int i = 0, mx = st.size(); i < mx; ++i) {
	  String S = st.get(i);
	  if (S.equals(s)) {
		size += f;
		st.set(i, "");
		return size;
	  } else if (S.indexOf("[") > 0) {
		size += f;
		Object o = typ.get(i);
		if (o != null) { // instantiated array
		  if (o.toString().indexOf("@") > 0) {
			int len = Array.getLength(o);
			if (len > 0) size += (4*len + sizeOf(o));	  
		  }
		}
		st.set(i, "");
		return size;
	  }
	}
	return size;
  }
  private static long getField(StringBuilder sb, List<Object> typ,
							   List<String> st, String s, int f) {
	long size = 0;
	for (int i = 0, mx = st.size(); i < mx; ++i) {
	  String S = st.get(i);
	  if (S.equals(s)) {
		size += f;
		sb.append(String.format("% 7d",f)+": "+S+ls);
		st.set(i, "");
		return size;
	  } else if (S.indexOf(s) > 0) {
		Object o = typ.get(i);
		if (o != null) {
		  if (o.toString().indexOf("@") > 0) {
			int len = Array.getLength(o);
			if (len > 0) {
			  long l = sizeOf(o);
			  size += (4 * len + l);
			  sb.append(String.format("% 7d",size)+": "+S.substring(0, S.length()-1)+len+"] "+ls);
			}
		  }
		} else sb.append(String.format("% 7d",f)+": "+S+ls);
		st.set(i, "");
		size += f;
		return size;
	  }
	}
	return size;
  }
  private static String toPrimitive(String S) {
		 if (S.indexOf("[J") >= 0) return "long";
	else if (S.indexOf("[D") >= 0) return "double";
	else if (S.indexOf("[I") >= 0) return "int";
	else if (S.indexOf("[F") >= 0) return "float";
	else if (S.indexOf("[S") >= 0) return "short";
	else if (S.indexOf("[C") >= 0) return "char";
	else if (S.indexOf("[B") >= 0) return "byte";
	else if (S.indexOf("[Z") >= 0) return "boolean";
	else if (S.indexOf("[L") >= 0) return "reference";
	return "";
  }
  private static int factor(String S) {
		 if (S.indexOf("[J") >= 0) return 8; // Long
	else if (S.indexOf("[D") >= 0) return 8; // Double
	else if (S.indexOf("[I") >= 0) return 4; // Integer
	else if (S.indexOf("[F") >= 0) return 4; // Float
	else if (S.indexOf("[S") >= 0) return 2; // Short
	else if (S.indexOf("[C") >= 0) return 2; // Char
	else if (S.indexOf("[B") >= 0) return 1; // Byte
	else if (S.indexOf("[Z") >= 0) return 1; // boolean
	else if (S.indexOf("[L") >= 0) return 4; // reference
	return 0;
  }
  private static int padding(long size) {
	int i = (int)(size % 8);
	return (i > 0)? 8-i:0;
  }
  private static String ls = System.lineSeparator();
}
 
Sửa lần cuối:

Joe

Thành viên VIP
21/1/13
2,935
1,299
113
8 Examples
1) Testint.java: One dimensional int[]
PHP:
public class Testint {
  private static String ls = System.lineSeparator();
  public static void printObjectSize(Object obj) {
	System.out.println("MemorySizeOf: int[]"+ls+
					   "Size:"+Mem.sizeOf(obj)+" bytes"+ls);
  }
  public static void printObjectStructure(Object obj) {
	System.out.println(Mem.structureOf(obj));
  }
 
  public static void main(String[] arguments) {
	int[] I = new int[10];
	for (int i = 0; i < 10; ++i) I[i] = i;
	System.out.println("-------int[]-------"+ls);
	printObjectSize(I);
	printObjectStructure(I);
  }
}
The output:
PHP:
C:\JFX\SizeOf>java Testint
-------int[]-------
 
MemorySizeOf: int[]
Size:56 bytes
 
MemoryStructureOf: int[10]
	  8: Header
	  4: Length
	  4: Reference
	 40: int[10]
	 56: Total in bytes
 
 
C:\JFX\SizeOf>
2) Test2D.java: One dimensional int[][]
PHP:
public class Test2D {
  private static String ls = System.lineSeparator();
  public static void printObjectSize(Object obj) {
	String CLS = obj.getClass().toString();
	System.out.println("MemorySizeOf: "+CLS.substring(CLS.lastIndexOf(".")+1)+ls+
					   "Size:"+Mem.sizeOf(obj)+" bytes"+ls);
  }
  public static void printObjectStructure(Object obj) {
	System.out.println(Mem.structureOf(obj));
  }
 
  public static void main(String[] arguments) {
	int[][] aAL = new int[10][];
	System.out.println("---------------Empty int[][]---------------");
	printObjectSize(aAL);
	printObjectStructure(aAL);
	for (int i = 0; i < 10; ++i) {
	  aAL[i] = new int[5];
	  for (int l = 0; l > 5; ++l) aAL[i][l] = l+i;
	}
	System.out.println("---------------int[][] with 10/5 elements---------------");
	printObjectSize(aAL);
	printObjectStructure(aAL);
  }
}
The output:
PHP:
C:\JFX\SizeOf>java Test2D
---------------Empty int[][]---------------
MemorySizeOf: class [[I
Size:176 bytes
 
MemoryStructureOf: int[10][]
	  8: Header
	  4: Length
	  4: Reference
	160: int[10][]
	176: Total in bytes
 
---------------int[][] with 10/5 elements---------------
MemorySizeOf: class [[I
Size:376 bytes
 
MemoryStructureOf: int[10][5]
	  8: Header
	  4: Length
	  4: Reference
	360: int[10][5]
	376: Total in bytes
 
 
C:\JFX\SizeOf>
3) Test3D.java: int[][][]
PHP:
  public static void main(String[] arguments) {
	int[][][] aAL = new int[10][][];
	System.out.println("---------------Empty int[][][]---------------");
	printObjectSize(aAL);
	printObjectStructure(aAL);
	// initialized as Irregular 3-Dim array
	for (int i = 0; i < 10; ++i) {
	  aAL[i] = new int[5][]; // <---irregular here
	  for (int l = 0; l > 5; ++l) {
		aAL[i][l] = new int[20];
		for (int n = 0; n < 20; ++n) aAL[i][l][n] = i*l*n+1;
	  }
	}
	System.out.println("---------------Irregular int[][][] with 10/5/20 elements---------------");
	printObjectSize(aAL);
	printObjectStructure(aAL);
 
	// regular Initialization
	for (int i = 0; i < 10; ++i) {
	  aAL[i] = new int[5][20]; // <---regular here
	  for (int l = 0; l > 5; ++l) {
		aAL[i][l] = new int[20];
		for (int n = 0; n < 20; ++n) aAL[i][l][n] = i*l*n+1;
	  }
	}
	System.out.println("---------------Regular int[][][] with 10/5/20 elements---------------");
	printObjectSize(aAL);
	printObjectStructure(aAL);
  }
The output:
PHP:
C:\JFX\SizeOf>java Test3D
---------------Empty int[][][]---------------
MemorySizeOf: class [[[I
Size:176 bytes
 
MemoryStructureOf: int[10][][]
	  8: Header
	  4: Length
	  4: Reference
	160: int[10][][]
	176: Total in bytes
 
---------------Irregular int[][][] with 10/5/20 elements---------------
MemorySizeOf: class [[[I
Size:976 bytes
 
MemoryStructureOf: int[10][5][]
	  8: Header
	  4: Length
	  4: Reference
	960: int[10][5][]
	976: Total in bytes
 
---------------Regular int[][][] with 10/5/20 elements---------------
MemorySizeOf: class [[[I
Size:4976 bytes
 
MemoryStructureOf: int[10][5][20]
	  8: Header
	  4: Length
	  4: Reference
   4960: int[10][5][20]
   4976: Total in bytes
 
 
C:\JFX\SizeOf>
4) TestA.java: ArrayList<Integer>
PHP:
public class TestA {
  private static String ls = System.lineSeparator();
  public static void printObjectSize(Object obj) {
	String CLS = obj.getClass().toString();
	System.out.println("MemorySizeOf: "+CLS.substring(CLS.lastIndexOf(".")+1)+ls+
					   "Size:"+Mem.sizeOf(obj)+" bytes"+ls);
  }
  public static void printObjectStructure(Object obj) {
	System.out.println(Mem.structureOf(obj));
  }
 
  public static void main(String[] arguments) {
	ArrayList<Integer>[] aAL = new ArrayList[10];
	System.out.println("---------------Empty ArrayList<Integer>---------------");
	printObjectSize(aAL);
	printObjectStructure(aAL);
	for (int i = 0; i < 10; ++i) {
	  aAL[i] = new ArrayList<>();
	  aAL[i].add(i);
	}
	System.out.println("---------------ArrayList<Integer> with 10 elements---------------");
	printObjectSize(aAL);
	printObjectStructure(aAL);
  }
}
The output:
PHP:
C:\JFX\SizeOf>java TestA
---------------Empty ArrayList<Integer>---------------
MemorySizeOf: ArrayList;
Size:56 bytes
 
MemoryStructureOf: ArrayList[]
	  8: Header
	  4: Length
	  4: Reference
	 40: ArrayList[10]
	 56: Total in bytes
 
---------------ArrayList<Integer> with 10 elements---------------
MemorySizeOf: ArrayList;
Size:536 bytes
 
MemoryStructureOf: ArrayList[]
	  8: Header
	  4: Length
	  4: Reference
	520: ArrayList[10]
	536: Total in bytes
 
 
C:\JFX\SizeOf>
5) TestH.java: HashMap<Integer, String>
PHP:
public class TestH {
  private static String ls = System.lineSeparator();
  public static void printObjectSize(Object obj) {
	String CLS = obj.getClass().toString();
	System.out.println("MemorySizeOf: "+CLS.substring(CLS.lastIndexOf(".")+1)+ls+
					   "Size:"+Mem.sizeOf(obj)+" bytes"+ls);
  }
  public static void printObjectStructure(Object obj) {
	System.out.println(Mem.structureOf(obj));
  }
 
  public static void main(String[] arguments) {
	HashMap<Integer, String> aAL = new HashMap<>();
	System.out.println("---------------Empty HashMap<Integer, String>---------------");
	printObjectSize(aAL);
	printObjectStructure(aAL);
	for (int i = 0; i < 10; ++i) {
	  aAL.put(i, "String_no."+i);
	}
	System.out.println("---------------HashMap<Integer, String> with 10 elements---------------");
	printObjectSize(aAL);
	printObjectStructure(aAL);
  }
}
The output:
PHP:
C:\JFX\SizeOf>java TestH
---------------Empty HashMap<Integer, String>---------------
MemorySizeOf: HashMap
Size:16 bytes
 
MemoryStructureOf: HashMap
	  8: Header
	  4: float
	  4: int
   null: HashMap$Node<K, V>[]
   null: Map$Entry<K, V>>
 
---------------HashMap<Integer, String> with 10 elements---------------
MemorySizeOf: HashMap
Size:456 bytes
 
MemoryStructureOf: HashMap
	  8: Header
	  4: float
	  4: int
   null: HashMap$Node<K, V>[]
   null: Map$Entry<K, V>>
	440: 40 elements of HashMap<Integer,String>
	456: Total in bytes
 
 
C:\JFX\SizeOf>
6) TestAA.java: ArrayList<Integer>[]
PHP:
public class TestAA {
  private static String ls = System.lineSeparator();
  public static void printObjectSize(Object obj) {
	String CLS = obj.getClass().toString();
	System.out.println("MemorySizeOf: "+CLS.substring(CLS.lastIndexOf(".")+1)+ls+
					   "Size:"+Mem.sizeOf(obj)+" bytes"+ls);
  }
  public static void printObjectStructure(Object obj) {
	System.out.println(Mem.structureOf(obj));
  }
 
  public static void main(String[] arguments) {
	ArrayList<Integer>[] aAL = new ArrayList[10];
	System.out.println("---------------Empty ArrayList<Integer>[]---------------");
	printObjectSize(aAL);
	printObjectStructure(aAL);
	for (int i = 0; i < 10; ++i) {
	  aAL[i] = new ArrayList<>();
	  aAL[i].add(i);
	}
	System.out.println("---------------ArrayList<Integer>[] with 10 elements---------------");
	printObjectSize(aAL);
	printObjectStructure(aAL);
  }
}
The output:
PHP:
C:\JFX\SizeOf>java TestAA
---------------Empty ArrayList<Integer>---------------
MemorySizeOf: ArrayList;
Size:56 bytes
 
MemoryStructureOf: ArrayList[]
	  8: Header
	  4: Length
	  4: Reference
	 40: ArrayList[10]
	 56: Total in bytes
 
---------------ArrayList<Integer> with 10 elements---------------
MemorySizeOf: ArrayList;
Size:536 bytes
 
MemoryStructureOf: ArrayList[]
	  8: Header
	  4: Length
	  4: Reference
	520: ArrayList[10]
	536: Total in bytes
 
 
C:\JFX\SizeOf>
7) TestString.java: String[]
PHP:
public class TestString {
  private static String ls = System.lineSeparator();
  public static void printObjectSize(Object obj) {
	System.out.println("MemorySizeOf: String[]"+ls+
					   "Size:"+Mem.sizeOf(obj)+" bytes"+ls);
  }
  public static void printObjectStructure(Object obj) {
	System.out.println(Mem.structureOf(obj));
  }
 
  public static void main(String[] arguments) {
	String[] I = new String[10];
	for (int i = 0; i < 10; ++i) I[i] = "String_No."+i;
	System.out.println("-------String[]-------"+ls);
	printObjectSize(I);
	printObjectStructure(I);
  }
}
The output:
PHP:
C:\JFX\SizeOf>java TestString
-------String[]-------
 
MemorySizeOf: String[]
Size:168 bytes
 
MemoryStructureOf: String[]
	  8: Header
	  4: Length
	  4: Reference
	150: String[10]
	  2: Padding
	166: Total in bytes
 
 
C:\JFX\SizeOf>
8) TestMyObj.java: user's JAVA object MyObj.java
PHP:
public  class MyObj {
  int[] I;
  double d;
  String s;
}
PHP:
public class TestMyObj {
  private static String ls = System.lineSeparator();
  public static void printObjectSize(Object obj) {
	System.out.println("MemorySizeOf: MyObj"+ls+
					   "Size:"+Mem.sizeOf(obj)+" bytes"+ls);
  }
  public static void printObjectStructure(Object obj) {
	System.out.println(Mem.structureOf(obj));
  }
 
  public static void main(String[] arguments) {
	MyObj mo = new MyObj();
	System.out.println("---------------Empty MyObj---------------");
	printObjectSize(mo);
	printObjectStructure(mo);
	mo.d = 1.5d;
	mo.I = new int[10];
	mo.s = "Hello Joe";
	for (int i = 0; i < 10; ++i) mo.I[i] = i;
	System.out.println("-------populated MyObj-------"+ls);
	printObjectSize(mo);
	printObjectStructure(mo);
  }
}
The output:
PHP:
C:\JFX\SizeOf>java TestMyObj
---------------Empty MyObj---------------
MemorySizeOf: MyObj
Size:24 bytes
 
MemoryStructureOf: MyObj
	  8: Header
	  8: double
   null: String
	  4: int[]
	  4: Padding
	 24: Total in bytes
 
-------populated MyObj-------
 
MemorySizeOf: MyObj
Size:136 bytes
 
MemoryStructureOf: MyObj
	  8: Header
	  8: double
	 13: String
	  3: Padding
	 96: int[10]
	  4: Padding
	136: Total in bytes
 
 
C:\JFX\SizeOf>
Have fun with JAVA Internals II
 
Sửa lần cuối: