java语言

查看java对象所占的内存大小的方法

时间:2022-12-04 20:19:34 java语言 我要投稿
  • 相关推荐

查看java对象所占的内存大小的方法

  做一些cache的时候,我们不可能把数据库的所有的数据都缓存到内存里面,我们要估计缓存的大小。那么如何查看java对象所占的内存大小呢?本文为大家介绍一下方法,希望可以为您提供帮助!更多内容请关注应届毕业生考试网!

  (1)做一些cache的时候,我们不可能把数据库的所有的数据都缓存到内存里面,我们要估计缓存的大小。

  (2)内存泄露的时候,我们可以查看某些对象的大小来定位问题,当然还有其他的更有效的方式,比如使用MAT分析dump文件

  (3)根据jvm的堆内存设置,我们可以知道最多可以创建多少个对象。

  从jdk5开始,提供了Instrumentation API,它有一个叫做getObjectSize()的方法,但是,这个方法存在两个问题:

  (1)不可以直接使用。必须要实现一个Instrumentation Agent,还得放到jar包里面。

  (2)它只能返回单个对象的大小,不能返回内部包含的子对象的大小。

  关于第一个问题,很好解决,在任何一个类里面声明一个"premain"方法,就可以把这个类做成是一个agent:

  public class SizeOfAgent {

  static Instrumentation inst;

  /** initializes agent */

  public static void premain(String agentArgs, Instrumentation instP) {

  inst = instP;

  }

  }

  jvm在启动的时候会调用premain()方法,同时会传递Instrumentation这个对象实例,要告诉jvm Instrumentation agent所在的类,需要把这个类打到jar包里面,

  然后在manifest.mf这个文件设置一些属性:

  Premain-Class: sizeof.agent.SizeOfAgent

  Boot-Class-Path:

  Can-Redefine-Classes: false

  java应用在启动的时候,指定-javaagent参数:

  java -javaagent:sizeofag.jar <Your main class>

  拿到Instrumentation这个实例以后,就可以调用sizeOf()方法了:

  public class SizeOfAgent {

  static Instrumentation inst;

  // ...

  public static long sizeOf(Object o) {

  return inst.getObjectSize(o);

  }

  }

  然后可以使用反射来获取子对象的大小。

  完整的代码如下:

  package com.bj58.test;

  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 {

  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<Object, Object> visited = new IdentityHashMap<Object, Object>();

  Stack<Object> stack = new Stack<Object>();

  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<Object, Object> visited) {

  if (obj instanceof String) {

  // skip interned string

  if (obj == ((String) obj).intern()) {

  return true;

  }

  }

  return (obj == null) // skip visited object

  || visited.containsKey(obj);

  }

  private static long internalSizeOf(Object obj, Stack<Object> stack,

  Map<Object, Object> 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;

  }

  }

  然后我们可以做一个测试:

  public class Test {

  static class Person{

  private int id;

  private String name;

  private String address;

  public Person(int id, String name, String address) {

  this.id = id;

  this.name = name;

  this.address = address;

  }

  }

  public static void main(String[] args) throws Exception {

  Person p = new Person(12, "xujsh","bj");

  long size = SizeOfAgent.fullSizeOf(p);

  System.out.println(size);

  }

  }

  切换到命令行:

  D:\workspace\objsize\src>java -version

  java version "1.6.0_22"

  Java(TM) SE Runtime Environment (build 1.6.0_22-b04)

  Java HotSpot(TM) Client VM (build 17.1-b03, mixed mode, sharing)

  D:\workspace\objsize\src>javac com/bj58/test/*.java

  D:\workspace\objsize\src>jar -cvfm size.jar MANIFEST.MF com/bj58/test/*

  标明清单(manifest)

  增加:com/bj58/test/SizeOfAgent.class(读入= 3119) (写出= 1698)(压缩了 45%)

  增加:com/bj58/test/SizeOfAgent.java(读入= 3147) (写出= 1204)(压缩了 61%)

  增加:com/bj58/test/Test$Person.class(读入= 442) (写出= 305)(压缩了 30%)

  增加:com/bj58/test/Test.class(读入= 692) (写出= 441)(压缩了 36%)

  增加:com/bj58/test/Test.java(读入= 509) (写出= 290)(压缩了 43%)

  D:\workspace\objsize\src>java -javaagent:size.jar com.bj58.test.Test

  24

  MANIFEST.MF:

  Manifest-Version: 1.0

  Main-Class: com.bj58.test.Test

  Premain-Class: com.bj58.test.SizeOfAgent

  Boot-Class-Path:

  Can-Redefine-Classes: false

  【注意】MANIFEST.MF文件的格式要求比较严格,每一行要满足:key:空格value回车

  \

  如何在web应用程序里面使用呢?

  以我的tomcat为例,

  (1)把size.jar上传tomcat的lib目录下面

  (2)修改catalina.sh:

  添加一行:

  JAVA_OPTS="$JAVA_OPTS -javaagent:$CATALINA_HOME/lib/size.jar"  //这一行是新添加的

  if [ -z "$LOGGING_MANAGER" ]; then

  JAVA_OPTS="$JAVA_OPTS -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager"

  else

  JAVA_OPTS="$JAVA_OPTS $LOGGING_MANAGER"

  fi

  (3)在应用里面添加一个controler:

  @Path(value = "/api/size")

  @GET

  public ActionResult size() {

  Map<Long, List<Long>> map = ApiUtils.getHotindexBaidu();

  long size = SizeOfAgent.fullSizeOf(map);

  return new ApiActionResult("size:"+size);

  }

【查看java对象所占的内存大小的方法】相关文章:

Java面向对象知识巩固09-28

Java获取UTC时间的方法02-09

mac版java更新升级方法11-08

Java编程节省内存的方法12-16

关于java性能调优的方法08-19

Java编程中异常处理的方法12-16

java读文件写文件的方法04-28

总结Java垃圾回收器的方法和原理08-11

java判断字符串是否为数字的几个方法04-11

java将excel文件转换成pdf文件的方法04-29