用Java怎么测试一个对象所占的内存的大小?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了用Java怎么测试一个对象所占的内存的大小?相关的知识,希望对你有一定的参考价值。

参考技术A 这是一个测试的方法,参考网上的,具体可以看提供给你的网址

package com;

public class Sizeof
public static void main(String[] args) throws Exception
// Warm up all classes/methods we will use
runGC();
usedMemory();
// Array to keep strong references to allocated objects
final int count = 100000;
Object[] objects = new Object[count];

long heap1 = 0;
// Allocate count+1 objects, discard the first one
for (int i = -1; i < count; ++i)
Object object = null;

// Instantiate your data here and assign it to object

object = new Object();
// object = new Integer (i);
// object = new Long (i);
// object = new String ();
// object = new byte [128][1]

if (i >= 0)
objects[i] = object;
else
object = null; // Discard the warm up object
runGC();
heap1 = usedMemory(); // Take a before heap snapshot


runGC();
long heap2 = usedMemory(); // Take an after heap snapshot:

final int size = Math.round(((float) (heap2 - heap1)) / count);
System.out.println("'before' heap: " + heap1 + ", 'after' heap: "
+ heap2);
System.out.println("heap delta: " + (heap2 - heap1) + ", "
+ objects[0].getClass() + " size = " + size + " bytes");
for (int i = 0; i < count; ++i)
objects[i] = null;
objects = null;


private static void runGC() throws Exception
// It helps to call Runtime.gc()
// using several method calls:
for (int r = 0; r < 4; ++r)
_runGC();


private static void _runGC() throws Exception
long usedMem1 = usedMemory(), usedMem2 = Long.MAX_VALUE;
for (int i = 0; (usedMem1 < usedMem2) && (i < 500); ++i)
s_runtime.runFinalization();
s_runtime.gc();
Thread.currentThread().yield();

usedMem2 = usedMem1;
usedMem1 = usedMemory();



private static long usedMemory()
return s_runtime.totalMemory() - s_runtime.freeMemory();


private static final Runtime s_runtime = Runtime.getRuntime();

参考资料:http://andyao.javaeye.com/blog/146124

本回答被提问者采纳
参考技术B 声明一个集合,放你要的对象,集合相当于数组,测试它里的内容所占的空间就可以了。 参考技术C 你自己统计类成员变量吧,还包括父类的成员变量,这个是最小的容量。统计这个没什么意义把,有时候父类的东西都私有的你没发统计。 参考技术D 用破解版的

如何获取一个Java对象所占内存大小

新建一个maven工程

我们先在IDEA中新建一个名为ObjectSizeFetcherAgent的maven工程,如下图: 

技术图片

 

 

在maven项目中的pom.xml中新增一个打jar包的插件,如下:

  <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <testExcludes>
                        <testExclude>/src/test/**</testExclude>
                    </testExcludes>
                    <encoding>utf-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>3.0.2</version>
                <configuration>
                    <archive>
                        <!--使用manifestFile属性配置自定义的参数文件所在的-->
                        <manifestFile>$project.build.outputDirectory/META-INF/MANIFEST.MF</manifestFile>
                    </archive>
                </configuration>
            </plugin>
        </plugins>
    </build>

  在项目的resources中新建一个名为META-INF的目录,在这个目录下新建一个名为MANIFEST.MF的属性文件,如下图:

技术图片

 

 

 项目的JDK设置为1.8,如下图:

技术图片

 

 技术图片

 

 

技术图片

 

 

编写获取Java对象内存的工具方法

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;

public class ObjectSizeFetcher 
    // instrumentation 是一个 java.lang.instrument.Instrumentation 的实例,由 JVM 自动传入
    private static Instrumentation instrumentation;

    /**
     *  这个方法先于主方法(main)执行
     * @param args
     * @param inst
     */
    public static void premain(String args, Instrumentation inst) 
        instrumentation = inst;
    

    /**
     *  直接计算当前对象占用空间大小,包括当前类及超类的基本类型实例字段大小、
     *  引用类型实例字段引用大小、实例基本类型数组总占用空间、实例引用类型数组引用本身占用空间大小;
     *  但是不包括超类继承下来的和当前类声明的实例引用字段的对象本身的大小、实例引用数组引用的对象本身的大小
     *
     * @param o 需要计算内存的对象
     * @return 返回内存大小
     */
    public static long sizeOf(Object o) 
        return instrumentation.getObjectSize(o);
    

    /**
     * 递归计算当前对象占用空间总大小,包括当前类和超类的实例字段大小以及实例字段引用对象大小
     * 注意:这个方法如果你看不懂也没关系,会用就行 
     *
     * @param objP
     * @return
     * @throws IllegalAccessException
     */
    public static long fullSizeOf(Object objP) throws IllegalAccessException 
        Set<Object> visited = new HashSet<Object>();
        Deque<Object> toBeQueue = new ArrayDeque<>();
        toBeQueue.add(objP);
        long size = 0L;
        while (toBeQueue.size() > 0) 
            Object obj = toBeQueue.poll();
            //sizeOf的时候已经计基本类型和引用的长度,包括数组
            size += skipObject(visited, obj) ? 0L : sizeOf(obj);
            Class<?> tmpObjClass = obj.getClass();
            if (tmpObjClass.isArray()) 
                //[I , [F 基本类型名字长度是2
                if (tmpObjClass.getName().length() > 2) 
                    for (int i = 0, len = Array.getLength(obj); i < len; i++) 
                        Object tmp = Array.get(obj, i);
                        if (tmp != null) 
                            //非基本类型需要深度遍历其对象
                            toBeQueue.add(Array.get(obj, i));
                        
                    
                
             else 
                while (tmpObjClass != null) 
                    Field[] fields = tmpObjClass.getDeclaredFields();
                    for (Field field : fields) 
                        if (Modifier.isStatic(field.getModifiers())   //静态不计
                                || field.getType().isPrimitive())     //基本类型不重复计
                            continue;
                        

                        field.setAccessible(true);
                        Object fieldValue = field.get(obj);
                        if (fieldValue == null) 
                            continue;
                        
                        toBeQueue.add(fieldValue);
                    
                    tmpObjClass = tmpObjClass.getSuperclass();
                
            
        
        return size;
    

    /**
     * String.intern的对象不计;计算过的不计,也避免死循环
     *
     * @param visited
     * @param obj
     * @return
     */
    static boolean skipObject(Set<Object> visited, Object obj) 
        if (obj instanceof String && obj == ((String) obj).intern()) 
            return true;
        
        return visited.contains(obj);
    


  

计算一个对象的大小

我们在项目工程中新建一个名为Point的类,然后写一个main方法来测试new Point()占用内存空间的大小,代码如下:

public class Point 
    private int x;
    private int y;

    public static void main(String [] args) 
        System.out.println(ObjectSizeFetcher.sizeOf(new Point()));
    

  

 

我们在文件resources/META-INF/MANIFEST.MF中新增如下一行属性配置:

Premain-Class: com.twq.ObjectSizeFetcher

  

技术图片

 

 

 

maven打包,如下:

技术图片

 

 

 

 打开操作系统的cmd,进入到上面的jar包所在的目录,如下图:

技术图片

 

 执行如下的命令:

java -javaagent:ObjectSizeFetcherAgent-1.0-SNAPSHOT.jar Point

  

得到的结果如下:

技术图片

 

 

 

技术图片

 

以上是关于用Java怎么测试一个对象所占的内存的大小?的主要内容,如果未能解决你的问题,请参考以下文章

如何计算Java对象所占内存的大小

C++类对象所占的内存空间

C#如何得到一个Image对象所占的字节数?

Java我可以主动去释放对象占的内存吗?可以的怎释放?

Java中关于“=”和“==”的分析

一个Java对象到底占用多大内存