新建一个maven工程

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

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

  1. <build>
  2. <plugins>
  3. <plugin>
  4. <groupId>org.apache.maven.plugins</groupId>
  5. <artifactId>maven-compiler-plugin</artifactId>
  6. <version>3.1</version>
  7. <configuration>
  8. <source>1.8</source>
  9. <target>1.8</target>
  10. <testExcludes>
  11. <testExclude>/src/test/**</testExclude>
  12. </testExcludes>
  13. <encoding>utf-8</encoding>
  14. </configuration>
  15. </plugin>
  16. <plugin>
  17. <groupId>org.apache.maven.plugins</groupId>
  18. <artifactId>maven-jar-plugin</artifactId>
  19. <version>3.0.2</version>
  20. <configuration>
  21. <archive>
  22. <!--使用manifestFile属性配置自定义的参数文件所在的-->
  23. <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
  24. </archive>
  25. </configuration>
  26. </plugin>
  27. </plugins>
  28. </build>

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

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

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

  1. import java.lang.instrument.Instrumentation;
  2. import java.lang.reflect.Array;
  3. import java.lang.reflect.Field;
  4. import java.lang.reflect.Modifier;
  5. import java.util.ArrayDeque;
  6. import java.util.Deque;
  7. import java.util.HashSet;
  8. import java.util.Set;
  9.  
  10. public class ObjectSizeFetcher {
  11. // instrumentation 是一个 java.lang.instrument.Instrumentation 的实例,由 JVM 自动传入
  12. private static Instrumentation instrumentation;
  13.  
  14. /**
  15. * 这个方法先于主方法(main)执行
  16. * @param args
  17. * @param inst
  18. */
  19. public static void premain(String args, Instrumentation inst) {
  20. instrumentation = inst;
  21. }
  22.  
  23. /**
  24. * 直接计算当前对象占用空间大小,包括当前类及超类的基本类型实例字段大小、
  25. * 引用类型实例字段引用大小、实例基本类型数组总占用空间、实例引用类型数组引用本身占用空间大小;
  26. * 但是不包括超类继承下来的和当前类声明的实例引用字段的对象本身的大小、实例引用数组引用的对象本身的大小
  27. *
  28. * @param o 需要计算内存的对象
  29. * @return 返回内存大小
  30. */
  31. public static long sizeOf(Object o) {
  32. return instrumentation.getObjectSize(o);
  33. }
  34.  
  35. /**
  36. * 递归计算当前对象占用空间总大小,包括当前类和超类的实例字段大小以及实例字段引用对象大小
  37. * 注意:这个方法如果你看不懂也没关系,会用就行
  38. *
  39. * @param objP
  40. * @return
  41. * @throws IllegalAccessException
  42. */
  43. public static long fullSizeOf(Object objP) throws IllegalAccessException {
  44. Set<Object> visited = new HashSet<Object>();
  45. Deque<Object> toBeQueue = new ArrayDeque<>();
  46. toBeQueue.add(objP);
  47. long size = 0L;
  48. while (toBeQueue.size() > 0) {
  49. Object obj = toBeQueue.poll();
  50. //sizeOf的时候已经计基本类型和引用的长度,包括数组
  51. size += skipObject(visited, obj) ? 0L : sizeOf(obj);
  52. Class<?> tmpObjClass = obj.getClass();
  53. if (tmpObjClass.isArray()) {
  54. //[I , [F 基本类型名字长度是2
  55. if (tmpObjClass.getName().length() > 2) {
  56. for (int i = 0, len = Array.getLength(obj); i < len; i++) {
  57. Object tmp = Array.get(obj, i);
  58. if (tmp != null) {
  59. //非基本类型需要深度遍历其对象
  60. toBeQueue.add(Array.get(obj, i));
  61. }
  62. }
  63. }
  64. } else {
  65. while (tmpObjClass != null) {
  66. Field[] fields = tmpObjClass.getDeclaredFields();
  67. for (Field field : fields) {
  68. if (Modifier.isStatic(field.getModifiers()) //静态不计
  69. || field.getType().isPrimitive()) { //基本类型不重复计
  70. continue;
  71. }
  72.  
  73. field.setAccessible(true);
  74. Object fieldValue = field.get(obj);
  75. if (fieldValue == null) {
  76. continue;
  77. }
  78. toBeQueue.add(fieldValue);
  79. }
  80. tmpObjClass = tmpObjClass.getSuperclass();
  81. }
  82. }
  83. }
  84. return size;
  85. }
  86.  
  87. /**
  88. * String.intern的对象不计;计算过的不计,也避免死循环
  89. *
  90. * @param visited
  91. * @param obj
  92. * @return
  93. */
  94. static boolean skipObject(Set<Object> visited, Object obj) {
  95. if (obj instanceof String && obj == ((String) obj).intern()) {
  96. return true;
  97. }
  98. return visited.contains(obj);
  99. }
  100.  
  101. }

  

计算一个对象的大小

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

  1. public class Point {
  2. private int x;
  3. private int y;
  4.  
  5. public static void main(String [] args) {
  6. System.out.println(ObjectSizeFetcher.sizeOf(new Point()));
  7. }
  8. }

  

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

  1. Premain-Class: com.twq.ObjectSizeFetcher

  

maven打包,如下:

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

执行如下的命令:

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

  

得到的结果如下:

如何获取一个Java对象所占内存大小的更多相关文章

  1. 4种方法教你如何查看java对象所占内存大小

    摘要:本文讲述4种查看java对象所占内存大小的方法 本文分享自华为云社区<查看java对象所占内存大小>,作者:xiewenci. 计算java对象所占内存大小 1.使用jdk8自带AP ...

  2. 复杂Java对象所占内存的大小

    我们在Java单个对象内存布局中讲解了单个简单的Java对象所占内存的大小的计算.那么这篇文章主要是讲解复杂Java对象所占内存大小的计算,我们把继承.复合的对象称为复杂对象 继承对象 class P ...

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

    [ 简单总结: 随便一个java项目,引入jar包: lucene-core-4.0.0.jar 如果是 maven项目,直接用如下依赖: <dependency> <groupId ...

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

    最近在读<深入理解Java虚拟机>,对Java对象的内存布局有了进一步的认识,于是脑子里自然而然就有一个很普通的问题,就是一个Java对象到底占用多大内存? 在网上搜到了一篇博客讲的非常好 ...

  5. 一个Java对象到底占多大内存?(转)

    最近在读<深入理解Java虚拟机>,对Java对象的内存布局有了进一步的认识,于是脑子里自然而然就有一个很普通的问题,就是一个Java对象到底占用多大内存? 在网上搜到了一篇博客讲的非常好 ...

  6. 【转】一个Java对象到底占多大内存?

    最近在读<深入理解Java虚拟机>,对Java对象的内存布局有了进一步的认识,于是脑子里自然而然就有一个很普通的问题,就是一个Java对象到底占用多大内存? 在网上搜到了一篇博客讲的非常好 ...

  7. 获取JAVA对象占用的内存大小

    介绍两种获取JAVA对象内存大小的方法. 第一种:Instrumentation 简介: 使用java.lang.instrument 的Instrumentation来获取一个对象的内存大小.利用I ...

  8. JAVA数组所占内存大小的对比

    1.两个数据模型 第一个是基本类型数组,第二个使用的是Float对象数组 public class SummaryModel{ private float[] summaryData; public ...

  9. 高端面试必备:一个Java对象占用多大内存

    这个问题一般会出现在稍微高端一点的 Java 面试环节.要求面试者不仅对 Java 基础知识熟悉,更重要的是要了解内存模型. Java 对象模型 HotSpot JVM 使用名为 oops (Ordi ...

随机推荐

  1. js玩命加载……

    在请求数据加载的过程中,经常需要显示请求等待,写了一个简单的请求等待—- html代码如下 <!--页面载入显示--> <div id="dataLoad" st ...

  2. Java开发笔记(一百一十)GET方式的HTTP调用

    所谓术业有专攻,一个程序单靠自身难以吃成大胖子,要想让程序变得血肉丰满,势必令其与外界多加交流,汲取天地之精华,方能练就盖世功夫.那么程序应当如何与外部网络进行通信呢?计算机网络的通信标准主要采取TC ...

  3. python实战项目 — 爬取 妹子图网,保存图片到本地

    重点: 1. 用def函数 2. 使用 os.path.dirname("路径保存") , 实现每组图片保存在独立的文件夹中 方法1: import requests from l ...

  4. Git手册(一):基本操作

    Git小册 本手册参考自runoob及其他网络资源,仅用于学习交流 Git工作流程   一般工作流程   1.克隆 Git 资源作为工作目录.   2.在克隆的资源上添加或修改文件.   3.如果其他 ...

  5. 使用DOS命令登录管理员并添加账号管理员权限

    runas /user:administrator cmd Password: compmgmt.msc

  6. Java中关于Math的几个取整方法的区别

    1.Math.ceil()   向上取整 System.out.println(Math.ceil(3.4)); //输出4 System.out.println(Math.ceil(3.7)); / ...

  7. iOS - xcode经常报的经典error解决办法大全

    1.错误信息: 2015-10-28 10:39:55.933 XFW[2696:55982] *** Assertion failure in -[UITableView _configureCel ...

  8. git下,输入git log 进入log 怎么退出

    解决方案: 英文状态下按Q就可以了 ctrl + c (应该是Linux命令中断的意思,很多中断都是这个命令). Paste_Image.png

  9. css实现 textarea 高度自适应

    此textarea非彼textarea ,有经验的老司机们应该知道html标签contenteditable这个属性. 利用此属性使当前的标签成为可以输入的状态,等同于输入框. 演示地址:https: ...

  10. Js网站开发学习第一天

    1.登录时,记住密码单选框,鼠标移上去显示div里的内容,移开则消失: <head> <meta http-equiv="Content-Type" conten ...