JVM-如何计算一个java对象的大小

本文介绍两种测量Java对象堆内存大小的方法:直接使用Instrumentation API和递归计算包含的所有对象大小,提供了具体实现代码和测试案例。
上一篇文章中介绍了java对象的堆内存结构
这里我们讨论下如何获取一个java对象的堆内存大小


使用什么方式获取java对象堆内存大小?
1.使用Instrumentation类的getObjectSize(Object obj)方法可获取
2.使用Instrumentation提供的方法获取堆内存只包括基本类型及引用类型本身的大小,不包括引用对象的大小
3.可通过递归的形式实现获取java对象完整的堆内存大小
4.使用Instrumentation方式,需要将工程打成jar包,并在MANIFEST.MF文件中指定Premain-Class和Main-Class属性
5.执行:java -javaagent:xxx.jar -jar xxx.jar


具体操作步骤如下:
1.代码实现:

具体业务实现类ObjectSizeService:

package com.object.service;

import java.lang.instrument.Instrumentation;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.HashSet;
import java.util.Set;

/**
 * @author ignore1992
 *
 * 2018-6-26
 */
public class ObjectSizeService
{
	/**
	 * 声明Instrumentation实例
	 */
	static Instrumentation instrument;
	
	public static void premain(String args, Instrumentation inst)
	{
		//通过premain函数给Instrumentation实例赋值
		instrument = inst;
	}
	
	/**
	 * 第一种方法:
	 * 计算当前对象占用空间大小,包括:当前类及超类基本类型实例大小、引用类型引用大小、基本类型数组占用空间大小、引用类型数组引用本身大小
	 * 					不包括:当前类及超类继承下来的引用对象大小、引用类型数组对象大小
	 * @param obj .
	 * @return .
	 */
	public static long sizeOf(Object obj)
	{
		return instrument.getObjectSize(obj);
	}
		
	/**
	 * 第二种方法:
	 * 计算当前对象占用空间的总大小,包括:当前类及超类基本类型实例大小、引用类型引用大小、基本类型数组占用空间大小、引用类型数组引用本身大小、当前类及超类继承下来的引用对象大小、引用类型数组对象大小
	 * @param obj .
	 * @return .
	 * @throws Exception .
	 */
	public static long fullSizeOf(Object obj)
	{
		long size = 0;
		Set<Object> visited = new HashSet<Object>();
		Deque<Object> queue = new ArrayDeque<Object>();
		queue.add(obj);
		while(queue.size() > 0)
		{
			Object tmpObj = queue.poll();
			//已经计算的过的不做计算
			size += visited.contains(tmpObj) ? 0 : sizeOf(tmpObj);
			Class<?> tmpClass = tmpObj.getClass();
			//数组需要进行遍历
			if(tmpClass.isArray())
			{
				//判断是否是非基本类型,基本类型类名称长度为2,非基本类型长度名称大于2
				if(tmpClass.getName().length() > 2)
				{
					//获取数组长度
					int length = Array.getLength(tmpObj);
					for(int i = 0; i < length; i++)
					{
						//获取数组元素
						Object tmp = Array.get(obj, i);
						if(tmp != null)
						{
							//因为非基本类型元素对象未做计算,要添加到队列中,做递归计算
							queue.add(tmp);
						}
					}
				}
			}
			else
			{
				while(tmpClass != null)
				{
					Field[] fields = tmpClass.getDeclaredFields();
					for(Field field : fields)
					{
						//判断修饰符是否是静态类型(静态类型变量属于类属性) 判断是否是基本类型(已经做了计算)
						if(Modifier.isStatic(field.getModifiers()) || field.getType().isPrimitive())
						{
							continue;
						}
						
						field.setAccessible(true);
						Object fieldValue = null;
						try
						{
							fieldValue = field.get(tmpObj);
						} 
						catch (Exception e)
						{
							System.out.println(e.getMessage());
						}
						
						if(fieldValue != null)
						{
							//非基本类型值放到队列中进行计算
							queue.add(fieldValue);
						}
					}
					//获取超类
					tmpClass = tmpClass.getSuperclass();
				}
			}
		}
		return size;
	}
}

测试类:

package com.object.test;

import com.object.service.ObjectSizeService;

/**
 * @author ignore1992
 *
 * 2018-6-26
 */
public class Main
{
	public static void main(String[] args)
	{
		//1.测试非基本类型对象大小
		System.out.println(String.format("sizeof(new A):%s", ObjectSizeService.sizeOf(new A())));
		System.out.println(String.format("fullsizeof(new A):%s", ObjectSizeService.fullSizeOf(new A())));
		System.out.println(String.format("sizeof(new B):%s", ObjectSizeService.sizeOf(new B())));
		System.out.println(String.format("fullsizeof(new B):%s", ObjectSizeService.fullSizeOf(new B())));
		
		//2.测试基本类型数组对象的大小
		System.out.println(String.format("sizeof(new int[1]):%s", ObjectSizeService.sizeOf(new int[1])));
		System.out.println(String.format("fullsizeof(new int[1]):%s", ObjectSizeService.fullSizeOf(new int[1])));
		System.out.println(String.format("sizeof(new int[2]):%s", ObjectSizeService.sizeOf(new int[2])));
		System.out.println(String.format("fullsizeof(new int[2]):%s", ObjectSizeService.fullSizeOf(new int[2])));
		System.out.println(String.format("sizeof(new int[3]):%s", ObjectSizeService.sizeOf(new int[3])));
		System.out.println(String.format("fullsizeof(new int[3]):%s", ObjectSizeService.fullSizeOf(new int[3])));
		
		
		//3.测试非基本类型数组对象的大小
		System.out.println(String.format("sizeof(new Integer[1]):%s", ObjectSizeService.sizeOf(new Integer[1])));
		System.out.println(String.format("fullsizeof(new Integer[1]):%s", ObjectSizeService.fullSizeOf(new Integer[1])));
		System.out.println(String.format("sizeof(new Integer[2]):%s", ObjectSizeService.sizeOf(new Integer[2])));
		System.out.println(String.format("fullsizeof(new Integer[2]):%s", ObjectSizeService.fullSizeOf(new Integer[2])));
		System.out.println(String.format("sizeof(new Integer[3]):%s", ObjectSizeService.sizeOf(new Integer[3])));
		System.out.println(String.format("fullsizeof(new Integer[3]):%s", ObjectSizeService.fullSizeOf(new Integer[3])));
		
		//4.测试非基本类型数组对象的大小
		System.out.println(String.format("sizeof(new A[1]):%s", ObjectSizeService.sizeOf(new A[1])));
		System.out.println(String.format("fullsizeof(new A[1]):%s", ObjectSizeService.fullSizeOf(new A[1])));
		System.out.println(String.format("sizeof(new A[2]):%s", ObjectSizeService.sizeOf(new A[2])));
		System.out.println(String.format("fullsizeof(new A[2]):%s", ObjectSizeService.fullSizeOf(new A[2])));
		System.out.println(String.format("sizeof(new A[3]):%s", ObjectSizeService.sizeOf(new A[3])));
		System.out.println(String.format("fullsizeof(new A[3]):%s", ObjectSizeService.fullSizeOf(new A[3])));
		
		//5.测试存在继承关系的非基本类型数组对象的大小
		System.out.println(String.format("sizeof(new B[1]):%s", ObjectSizeService.sizeOf(new B[1])));
		System.out.println(String.format("fullsizeof(new B[1]):%s", ObjectSizeService.fullSizeOf(new B[1])));
		System.out.println(String.format("sizeof(new B[2]):%s", ObjectSizeService.sizeOf(new B[2])));
		System.out.println(String.format("fullsizeof(new B[2]):%s", ObjectSizeService.fullSizeOf(new B[2])));
		System.out.println(String.format("sizeof(new B[3]):%s", ObjectSizeService.sizeOf(new B[3])));
		System.out.println(String.format("fullsizeof(new B[3]):%s", ObjectSizeService.fullSizeOf(new B[3])));
	}
}

class A
{
	int a = 0;
	String str = "123456";
}

class B extends A
{
	int b = 0;
	String str1 = "12345678";
}

参考:https://www.cnblogs.com/magialmoon/p/3757767.html

完整代码路径如下:

https://github.com/ingorewho/common-tools/tree/master/java-objectsize


2.使用maven方式在eclipse下将工程打成jar包

首先在pom.xml文件中添加相关插件:

<build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>3.0.0</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                            <transformers>
                                <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                    <manifestEntries>
										#指定MANIFEST.MF文件中Main-Class属性
                                    	<Main-Class>com.object.test.Main</Main-Class>
										#指定MANIFEST.MF文件中Premain-Class属性
                                    	<Premain-Class>com.object.service.ObjectSizeService</Premain-Class>
                                    </manifestEntries>
                                </transformer>
                            </transformers>
                            <artifactSet>
                            </artifactSet>
                            <!--<outputFile>${project.build.directory}/${project.artifactId}-${project.version}-fat.jar</outputFile>-->
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
 </build>
右键工程->Run As->Maven Install,生成jar文件如下:

工程目录\工程名称\target\java-objectsize-0.0.1-SNAPSHOT.jar

3.在装有jdk环境的服务器上执行jar文件

执行命令:

java -javaagent:java-objectsize-0.0.1-SNAPSHOT.jar -jar java-objectsize-0.0.1-SNAPSHOT.jar

输出打印:

sizeof(new A):24
fullsizeof(new A):80
sizeof(new B):32
fullsizeof(new B):144
sizeof(new int[1]):24
fullsizeof(new int[1]):24
sizeof(new int[2]):24
fullsizeof(new int[2]):24
sizeof(new int[3]):32
fullsizeof(new int[3]):32
sizeof(new Integer[1]):24
fullsizeof(new Integer[1]):24
sizeof(new Integer[2]):24
fullsizeof(new Integer[2]):24
sizeof(new Integer[3]):32
fullsizeof(new Integer[3]):32
sizeof(new A[1]):24
fullsizeof(new A[1]):24
sizeof(new A[2]):24
fullsizeof(new A[2]):24
sizeof(new A[3]):32
fullsizeof(new A[3]):32
sizeof(new B[1]):24
fullsizeof(new B[1]):24
sizeof(new B[2]):24
fullsizeof(new B[2]):24
sizeof(new B[3]):32
fullsizeof(new B[3]):32

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值