上一篇文章中介绍了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.代码实现:
参考:https://www.cnblogs.com/magialmoon/p/3757767.html
这里我们讨论下如何获取一个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
本文介绍两种测量Java对象堆内存大小的方法:直接使用Instrumentation API和递归计算包含的所有对象大小,提供了具体实现代码和测试案例。

2446

被折叠的 条评论
为什么被折叠?



