java统计空间占用_JVM —— Java 对象占用空间大小计算

引用类型(reference type: Integer)在 32 位系统上每一个占用 4bytes(即32bit, 才干管理 2^32=4G 的内存), 在 64 位系统上每一个占用 8bytes(开启压缩为 4 bytes)。

四. 对齐填充

HotSpot 的对齐方式为 8 字节对齐。不足的须要 Padding 填充对齐, 公式:(对象头 + 实例数据 + padding)% 8 == 0 (0<= padding <8)

五. 计算 Java 对象占用空间大小

借助 Instrument 接口的 getObjectSize 方法计算对象占用空间

SizeOfAgent: 计算对象大小类

package com.wenniuwuren.objectsizeof;

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;

/**

* 借助 Instrumentation 接口的 getObjectSize 方法计算对象占用空间

* 原来的 sizeOf 仅仅能计算本对象占用空间, 无法计算继承下来的占用空间,

* 只是能够用反射的方法把全部占用空间计算出来

*

* Created by zhuyb on 16/3/20.

*/

public class SizeOfAgent {

static Instrumentation instrumentation;

// 第一个參数由 –javaagent。 第二个參数由 JVM 传入

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

instrumentation = instP;

}

// 返回没有子类对象大小的大小

public static long sizeOf(Object o) {

if (instrumentation == 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 instrumentation.getObjectSize(o);

}

/**

*

* 计算复合对象

* @param obj object to calculate size of

* @return object size

*/

public static long fullSizeOf(Object obj) {

Map visited = new IdentityHashMap();

Stack stack = new Stack();

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

if (obj instanceof String) {

// String 池里已有的不再计算

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

return true;

}

}

return (obj == null) // 已有对象不再计算

|| visited.containsKey(obj);

}

private static long internalSizeOf(Object obj, Stack stack, Map 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);

// 处理全部数组内容

Class clazz = obj.getClass();

if (clazz.isArray()) {

// [I , [F 基本类型名字长度是2

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;

}

// 处理对象的全部字段

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;

} else {

// 使 private 属性可訪问

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;

}

}

使用上述代码必须将上述代码打成 jar 包, 而且 MANIFEST.MF 文件设置參数(

Premain-Class:sizeof.agent.SizeOfAgent

Boot-Class-Path:

Can-Redefine-Classes:false

)

假设使用 Maven 打包的话, 能够直接在 pom.xml 里面设置 MANIFEST.MF 的參数 :

maven-jar-plugin

2.4

SizeOfAgent

com.wenniuwuren.objectsizeof.SizeOfAgent

false

false

測试类: SizeOfAgentTest

package com.wenniuwuren.objectsizeof;

import static com.wenniuwuren.objectsizeof.SizeOfAgent.*;

/**

* 下面结果在 64-bit JVM 下測试

* 启动參数1(不压缩指针长度):-javaagent:target/SizeOfAgent.jar -XX:-UseCompressedOops

*

* Created by zhuyb on 16/3/20.

*/

public class SizeOfAgentTest {

public static void main(String[] args) {

System.out.println("------------------空对象----------------------------");

// 16 bytes + 0 + 0 = 16 空对象, 仅仅有对象头

System.out.println("sizeOf(new Object()) = " + sizeOf(new Object()));

System.out.println("fullSizeOf(new Object()) = " + fullSizeOf(new Object()));

System.out.println("----------------非空对象含有原始类型、引用类型------------------------------");

// 16 bytes + 8 + 4 + padding = 32

System.out.println("sizeOf(new A()) = " + sizeOf(new A()));

System.out.println("fullSizeOf(new A()) = " + fullSizeOf(new A()));

// 16 + 4 + padding =24 数据是一个 int

System.out.println("sizeOf(new Integer(1)) = " + sizeOf(new Integer(1)));

// (16 + int hash:4 + int hash32:4 + refer char value[]:8 + padding) = 32

// 静态属性(static)不计算空间。由于全部对象都是共享一块空间的

// 不同版本号JDK可能 String 内部 Field 可能不同,本次測试使用JDK1.7

System.out.println("sizeOf(new String()) = " + sizeOf(new String()));

// (16 + 4 + 4 + 8 + padding) + (24 + 0 + padding) = 56

System.out.println("fullSizeOf(new String()) = " + fullSizeOf(new String()));

// (16 + 4 + 4 + 8 + padding) = 32

System.out.println("sizeOf(new String('a')) = " + sizeOf(new String("a")));

// (16 + 4 + 4 + 8 +padding) + (24 + 2 + padding) = 64

System.out.println("fullSizeOf(new String('a')) = " + fullSizeOf(new String("a")));

System.out.println("-------------------原始类型数组对象---------------------------");

// 24 bytes + 0*1 + 0 = 24 数组长度为 0,所以仅仅有对象头的长度

System.out.println("sizeOf(new byte[0]) = " + sizeOf(new byte[0]));

System.out.println("fullSizeOf(new byte[0]) = " + fullSizeOf(new byte[0]));

// 24 + 1*1 + padding = 32

System.out.println("sizeOf(new byte[1]) = " + sizeOf(new byte[1]));

System.out.println("fullSizeOf(new byte[1]) = " + fullSizeOf(new byte[1]));

// 24 + 1*2 + padding = 32

System.out.println("sizeOf(new char[1]) = " + sizeOf(new char[1]));

System.out.println("fullSizeOf(new char[1]) = " + fullSizeOf(new char[1]));

// 24 + 9*1 + padding = 40

System.out.println("sizeOf(new byte[9]) = " + sizeOf(new byte[9]));

System.out.println("fullSizeOf(new byte[9]) = " + fullSizeOf(new byte[9]));

System.out.println("--------------------引用类型数组对象--------------------------");

// 24 bytes + 0*8 + 0 = 24 数组长度为 0

System.out.println("sizeOf(new Integer[0]) = " + sizeOf(new Integer[0]));

System.out.println("fullSizeOf(new Integer[0]) = " + fullSizeOf(new Integer[0]));

// 24 bytes + 1*8 + 0 = 32 引用对象 64-bit JVM 占用 8 bytes

System.out.println("sizeOf(new Integer[1]) = " + sizeOf(new Integer[1]));

System.out.println("fullSizeOf(new Integer[1]) = " + fullSizeOf(new Integer[1]));

// 24 bytes + 2*8 + padding = 40

System.out.println("sizeOf(new Integer[1]) = " + sizeOf(new Integer[1]));

System.out.println("fullSizeOf(new Integer[1]) = " + fullSizeOf(new Integer[1]));

// 24 + 3*8 + padding = 48

System.out.println("sizeOf(new Integer[3]) = " + sizeOf(new Integer[3]));

System.out.println("fullSizeOf(new Integer[3]) = " + fullSizeOf(new Integer[3]));

System.out.println("-------------------自己定义数组对象---------------------------");

// 16 + (4+8) + padding = 32

System.out.println("sizeOf(new B()) = " + sizeOf(new B()));

System.out.println("fullSizeOf(new B()) = " + fullSizeOf(new B()));

// 24 + 0*8 + padding = 24 引用对象 64-bit JVM 占用 8 bytes,

// 由于没创建真实的 new B()所以 B类内部数据还未占用空间

System.out.println("sizeOf(new B[0]) = " + sizeOf(new B[0]));

System.out.println("fullSizeOf(new B[0]) = " + fullSizeOf(new B[0]));

// 24 + 1*8 + padding = 32

System.out.println("sizeOf(new B[1]) = " + sizeOf(new B[1]));

System.out.println("fullSizeOf(new B[1]) = " + fullSizeOf(new B[1]));

// 24 + 2*8 + padding = 40

System.out.println("sizeOf(new B[2]) = " + sizeOf(new B[2]));

System.out.println("fullSizeOf(new B[2]) = " + fullSizeOf(new B[2]));

// 24 + 3*8 + padding = 48

System.out.println("sizeOf(new B[3]) = " + sizeOf(new B[3]));

System.out.println("fullSizeOf(new B[3]) = " + fullSizeOf(new B[3]));

System.out.println("-------------------复合对象---------------------------");

// 16 + (4+8) + padding = 32 sizeOf 仅仅计算单层次占用空间大小

System.out.println("sizeOf(new C()) = " + sizeOf(new C()));

// (16 + (4+8) + padding1) + (24 + 2*8 + padding2) + 2*(16 + (4+8) + padding3) = 136

// 递归计算当前对象占用空间总大小,包含当前类和超类的实例字段大小以及实例字段引用对象大小

System.out.println("fullSizeOf(new C()) = " + fullSizeOf(new C()));

System.out.println("-------------------继承关系---------------------------");

// 涉及继承关系的时候有一个最主要的规则:首先存放父类中的成员,接着才是子类中的成员, 父类也要依照 8 byte 规定

// 16 + 1 + padding = 24

System.out.println("sizeOf(new D()) = " + sizeOf(new D()));

System.out.println("fullSizeOf(new D()) = " + fullSizeOf(new D()));

// 16 + 父类(1 + padding1) + 1 + padding2 = 32

System.out.println("sizeOf(new E()) = " + sizeOf(new E()));

System.out.println("fullSizeOf(new E()) = " + fullSizeOf(new E()));

}

public static class A {

int a;

Integer b;

}

public static class B {

int a;

Integer b;

}

public static class C{

int c;

B[] b = new B[2];

// 初始化

C() {

for (int i = 0; i < b.length; i++) {

b[i] = new B();

}

}

}

public static class D {

byte d1;

}

public static class E extends D {

byte e1;

}

}

执行:

假设在 IDE 执行时须要设置 JVM 參数: -javaagent:target/SizeOfAgent.jar -XX:-UseCompressedOops;

假设在命令行执行命令: java -javaagent:sizeofag.jar

-XX:-UseCompressedOops 主类名称。

測试结果:

------------------空对象----------------------------

sizeOf(new Object()) = 16

fullSizeOf(new Object()) = 16

----------------非空对象含有原始类型、引用类型------------------------------

sizeOf(new A()) = 32

fullSizeOf(new A()) = 32

sizeOf(new Integer(1)) = 24

sizeOf(new String()) = 32

fullSizeOf(new String()) = 56

sizeOf(new String('a')) = 32

fullSizeOf(new String('a')) = 64

-------------------原始类型数组对象---------------------------

sizeOf(new byte[0]) = 24

fullSizeOf(new byte[0]) = 24

sizeOf(new byte[1]) = 32

fullSizeOf(new byte[1]) = 32

sizeOf(new char[1]) = 32

fullSizeOf(new char[1]) = 32

sizeOf(new byte[9]) = 40

fullSizeOf(new byte[9]) = 40

--------------------引用类型数组对象--------------------------

sizeOf(new Integer[0]) = 24

fullSizeOf(new Integer[0]) = 24

sizeOf(new Integer[1]) = 32

fullSizeOf(new Integer[1]) = 32

sizeOf(new Integer[1]) = 32

fullSizeOf(new Integer[1]) = 32

sizeOf(new Integer[3]) = 48

fullSizeOf(new Integer[3]) = 48

-------------------自己定义数组对象---------------------------

sizeOf(new B()) = 32

fullSizeOf(new B()) = 32

sizeOf(new B[0]) = 24

fullSizeOf(new B[0]) = 24

sizeOf(new B[1]) = 32

fullSizeOf(new B[1]) = 32

sizeOf(new B[2]) = 40

fullSizeOf(new B[2]) = 40

sizeOf(new B[3]) = 48

fullSizeOf(new B[3]) = 48

-------------------复合对象---------------------------

sizeOf(new C()) = 48

fullSizeOf(new C()) = 152

-------------------继承关系---------------------------

sizeOf(new D()) = 24

fullSizeOf(new D()) = 24

sizeOf(new E()) = 32

fullSizeOf(new E()) = 32

測试类中复合对象计算可能较为麻烦, 能够參照下图较为清楚地看出 new C() 的占用空间计算:

52f37cbda137270d0d267a4338807d51.png

六. 总结

总体的 Java 对象是依照一定规则进行的。 清楚了 JVM 对象的内存布局和分配规则。 计算 Java 对象的大小就比較简单了。

Java 不像 C++ 能够提供对象大小, 这是 Java 语言的设计初衷(自己主动内存管理), 可是随着对 Java 的深入了解。 又到了对 JVM (使用 C、C++ 实现) 底层实现的问题上。

本文的參考资料为 2007 年的, 至今已有 9 年, 參考资料内容至今还是有效的,JVM 相关的东西变动确实小,挺有意思的

七. 參考资料

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/393334.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

源于十年来的点滴积累——《变革中的思索》印行出版

源于归国十年来的点滴积累, 集结成书的《变革中的思索》&#xff0c;日前由电子工业出版社刊印出版。 这本书共有五个章节&#xff0c;分别是解码创新、中国智造、管理心得、我和微软、心灵记忆——前三章偏重技术&#xff0c;更多理性的思考; 后两章则工作生活中的所见所闻&am…

SpringBoot声明式事务

目录 事务的基本特征隔离级别传播行为Transcation事务的基本特征&#xff08;ACID&#xff09; Atomic&#xff08;原子性&#xff09; 事务中包含的操作被看作一个整体的业务单元&#xff0c;这个业务单元中的操作要么全部成功&#xff0c;要么全部失败&#xff0c;不会出现部…

团队作业——项目Alpha版本发布

---恢复内容开始--- https://edu.cnblogs.com/campus/xnsy/SoftwareEngineeringClass1 https://edu.cnblogs.com/campus/xnsy/SoftwareEngineeringClass1/homework/3329 <作业要求的链接> Gorious Computer <写上团队名称> 发布项目α版本&#xff0c;对项目…

MySQL异步复制

准备&#xff1a;主备库版本一致&#xff0c;正常安装软件。 1、主库上设置一个复制使用的账户&#xff1a; mysql> grant replication slave on *.* to rep1192.168.100.136 identified by dbking; Query OK, 0 rows affected (0.18 sec) mysql> select user,host,passw…

开源一个爬取redmine数据的测试报告系统

背景 软件测试的最后有一道比较繁琐的工作&#xff0c;就是编写测试报告。手写测试报告在数据统计和分析上面要耗费比较大的事件和精力。之前工作室使用mantis管理bug缺陷。公司有内部有个系统&#xff0c;可以直接从mantis上面获取数据并进行统计&#xff0c;生成一份测试报告…

使用.net Stopwatch class 来分析你的代码

当我们在调试&#xff0c;优化我们的代码的时候&#xff0c;想知道某段代码的真正的执行时间&#xff0c;或者我们怀疑某段代码&#xff0c;或是某几段代码执行比较慢&#xff0c; 需要得到具体的某段代码的具体执行时间的时候。有一个很好用的类Stopwatch。 Stopwatch 类在 Sy…

java衍生作用_java-如何从AffineTransform衍生的形状对象中“...

您可以使用AffineTransform.transform(Point2D, Point2D)变换多边形上的单个点.如果您不使用旋转变换来移动船,而是将船的位置保持在一个(x,y)位置,那么事情就简单得多.您可以在move()中移动飞船的位置,而不是尝试平移多边形.然后,当您想给船上油漆时,例如做&#xff1a;// Opt…

进程间通信 (IPC) 方法总结(三)

进程间通信 &#xff08;IPC&#xff09; 方法总结&#xff08;三&#xff09; 信号量&#xff08;SEMAPHORE&#xff09; 信号量是一个计数器&#xff0c;用于多进程对共享数据的访问&#xff0c;信号量的意图在于进程间同步。 为了获得共享资源&#xff0c;进程需要执行下列操…

实现离线加域---Windows2008 R2 新功能系列之八

我们都知道&#xff0c;部署活动目录&#xff0c;无非搭建一台或多台DC&#xff0c;然后把其它的客户端计算机或成员服务器全部加入域&#xff0c;但在windows2008SP2以前&#xff0c;客户端加入域时&#xff0c;DC必须在线&#xff0c;而从2008R2开始我们已经可以做到让客户端…

分表后需要注意的二三事

前言 本篇是上一篇《一次分表踩坑实践的探讨》&#xff0c;所以还没看过的朋友建议先看上文。 还是先来简单回顾下上次提到了哪些内容&#xff1a; 分表策略&#xff1a;哈希、时间归档等。分表字段的选择。数据迁移方案。而本篇文章的背景是在我们上线这段时间遇到的一些问题并…

DNS 原理

阮老师的作品&#xff0c;非常精彩&#xff0c;转载&#xff01; DNS 是互联网核心协议之一。不管是上网浏览&#xff0c;还是编程开发&#xff0c;都需要了解一点它的知识。 本文详细介绍DNS的原理&#xff0c;以及如何运用工具软件观察它的运作。我的目标是&#xff0c;读完此…

销售员/学员/讲师系统

前言: 今晚写一篇关于学员/讲师/销售员CRM系统。这个小项目是27号开始做的&#xff0c;大概搞了一星期不到。我把一些知识点总结下&#xff0c;还写下当时克服的BUG。 Django练习小项目&#xff1a;学员管理系统设计开发 带着项目需求学习是最有趣和效率最高的&#xff0c;今天…

java里面的 |运算符_Java 中 | ^ 运算符的简单使用

背景今天碰到了代码中的按位与运算&#xff0c;复习一下&#xff0c;先列一个各个进制数据表。顺便复习一下十进制转二进制的计算方式&#xff1a;接下来解释下这三个运算符&#xff1a;&  按位与&#xff0c;都转为二进制的情况下&#xff0c;同为1则为1&#xff0c;否则…

彻底理解正向代理、反向代理、透明代理

套用古龙武侠小说套路来说&#xff0c;代理服务技术是一门很古老的技术&#xff0c;是在互联网早期出现就使用的技术。一般实现代理技术的方式就是在服务器上安装代理服务软件&#xff0c;让其成为一个代理服务器&#xff0c;从而实现代理技术。常用的代理技术分为正向代理、反…

使用showMessageDialog显示消息框

-----------------siwuxie095 工程名&#xff1a;TestJOptionPane 包名&#xff1a;com.siwuxie095.showdialog 类名&#xff1a;TestMessageDialog.java 工程结构目录如下&#xff1a; 代码&#xff1a; package com.siwuxie095.showdialog; import java.awt.BorderLayout;…

NodeJS学习笔记(一)——搭建开发框架Express,实现Web网站登录验证

目录 开发环境  1、建立工程  2、目录结构  3、Express配置文件  4、Ejs模板  5、安装常用库及页面分离  6、路由  7、session  8、页面访问控制及提示JS是脚本语言&#xff0c;脚本语言都需要一个解析器才能运行。对于写在HTML页面里 的JS&#xff0c;浏览器充…

项目经理如何管理情绪?这三本书管理书籍你必须要看

本文主要是介绍三本管理的书籍&#xff0c;需要全部书籍的可以加Q群375508415去拿走。里面很多大神的PMP资料。 大家有没有觉得项目经理有时像个政委&#xff0c;做员工思想工作&#xff1b; 有时像个HR&#xff0c;操心员工的稳定和发展&#xff1b; 有时像个咨询顾问&#xf…

[RN] React Native 自定义导航栏随滚动渐变

React Native 自定义导航栏随滚动渐变 实现效果预览&#xff1a; 代码实现&#xff1a; 1、定义导航栏 NavPage.js import React, {Component} from react; import {View, Text, Image, StyleSheet, TouchableOpacity, Platform, Dimensions} from react-native;/*** 自定义导航…

【CSS 技能提升】 :before和:after的使用

前几天的晚上较全面的去看了下css的一些文档和资料&#xff0c;大部分的样式运用都没什么大问题了&#xff0c;只是有些许较陌生&#xff0c;但是也知道他们的存在和实现的是什么样式。今天主要想在这篇学习笔记中写的也不多&#xff0c;主要是针对:before和:after写一些内容&a…

成功试验基于C#/.NET的Android开发

今天最开心事情莫过于摸索验证了一个事情&#xff0c;C#也能进行Android和IOS开发&#xff0c;白天安装了开发环境&#xff0c;晚上进行测试&#xff0c;直到此时此刻&#xff0c;已经成功的导出一款基于C#/.NET的安卓APK&#xff0c;并且能够成功的导入到安卓手机运行&#xf…