jvm兩種方式獲取對象所佔用的內存

摘要: 在開發過程中,我們有時需要來獲取某個對象的大小,以方便我們參考,來決定開發的技術方案。jvm中提供了兩種方式來獲取一個對象的大小。

在開發過程中,我們有時需要來獲取某個對象的大小,以方便我們參考,來決定開發的技術方案。jvm中提供了兩種方式來獲取一個對象的大小。

通過Instrumentation來計算對象的大小

  • 編寫計算代碼:

package com.java.basic;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 SizeOfAgent {  private static Instrumentation inst;  /** initializes agent */  public static void premain(String agentArgs, Instrumentation instP)  {  inst = instP;  }  /** * Returns object size without member sub-objects. * @param o object to get size of * @return object size */  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 "-javaagent" command line argument.");  }  return inst.getObjectSize(o);  }  /** * Calculates full size of object iterating over * its hierarchy graph. * @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;  }  private static boolean skipObject(Object obj, Map visited)  {  if (obj instanceof String) {//這個if是bug,應當去掉--teasp  // skip interned string  if (obj == ((String) obj).intern()) {  return true;  }  }  return (obj == null) || visited.containsKey(obj);  }  @SuppressWarnings("rawtypes")  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 elements  Class clazz = obj.getClass();  if (clazz.isArray())  {  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 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()))  {  if (fields[i].getType().isPrimitive())  {  continue; // skip primitive fields  }  else  {  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;  } } 

其中sizeof方法僅僅獲取的是當前對象的大小,而該對象的如果存在對其他對象的引用,則不在計算範圍以內,而fullsizeof則會計算整體的大小。

  • 將該java文件進行編譯,並打成jar包

  1. com.java.basic.SizeOfAgent .java

jar cvf sizeOfAgent.jar com/java.basic/SizeOfAgent .class

  • 修改META-INF/MANIFEST.MF文件內容

    Premain-Class: com.java.basic.SizeOfAgent

Boot-Class-Path:

Can-Redefine-Classes: false

注意:每個冒號後面都有一個空格,且最後一行會有一個換行

  • 將該jar包導入項目

  • 添加啟動參數:-javaagent:E:\sizeOfAgent.jar

    我這邊是將該jar包放在e盤,這裡填寫絕對路徑。

這樣我們就可以通過調用該類中的sizeOf方法或者fullSizeOf方法即可。


分享到:


相關文章: