JVM —— Java 对象占用空间大小计算
- 缓存的实现: 在设计 JVM 内缓存时(不是借助 Memcached、 Redis 等), 须要知道缓存的对象是否会超过 JVM 最大堆限制, 假设会超过要设置对应算法如 LRU 来丢弃一部分缓存数据以满足兴许内容的缓存
- JVM 參数设置: 假设知道对象会被创建。 能够帮助推断 -Xmx 须要设置多少
- 仅仅是为了好玩
原生类型(primitive type)的内存占用例如以下:
Primitive Type | Memory Required(bytes) |
boolean | 1 |
byte | 1 |
short | 2 |
char | 2 |
int | 4 |
float | 4 |
long | 8 |
double | 8 |
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<Object, Object> visited = new IdentityHashMap<Object, Object>();
Stack<Object> stack = new Stack<Object>(); 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<Object, Object> 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<Object> stack, Map<Object, Object> 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;
} }
Can-Redefine-Classes: false
<!-- pom打jar包的时候设置MANIFEST.MF的key/value,能够通过在pom.xml文件里加入plugin的方式来实现 -->
<build>
<plugins>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<configuration>
<finalName>SizeOfAgent</finalName>
<archive>
<manifestEntries>
<Premain-class>com.wenniuwuren.objectsizeof.SizeOfAgent</Premain-class>
<Boot-Class-Path></Boot-Class-Path>
<Can-Redefine-Classes>false</Can-Redefine-Classes>
</manifestEntries>
<addMavenDescriptor>false</addMavenDescriptor>
</archive>
</configuration>
</plugin>
</plugins>
</build>
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;
} }
-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() 的占用空间计算:
JVM —— Java 对象占用空间大小计算的更多相关文章
- 如何准确计算Java对象的大小
如何准确计算Java对象的大小 原创文章,转载请注明:博客园aprogramer 原文链接:如何准确计算Java对象的大小 有时,我们需要知道Java对象到底占用多少内存,有人通过连续调用两 ...
- 如何精确地测量java对象的大小-底层instrument API
转载: 如何精确地测量java对象的大小-底层instrument API 关于java对象的大小测量,网上有很多例子,大多数是申请一个对象后开始做GC,后对比前后的大小,不过这样,虽然说这样测量对象 ...
- 计算Java对象内存大小
摘要 本文以如何计算Java对象占用内存大小为切入点,在讨论计算Java对象占用堆内存大小的方法的基础上,详细讨论了Java对象头格式并结合JDK源码对对象头中的协议字段做了介绍,涉及内存模型.锁原理 ...
- Ehcache计算Java对象内存大小
在EHCache中,可以设置maxBytesLocalHeap.maxBytesLocalOffHeap.maxBytesLocalDisk值,以控制Cache占用的内存.磁盘的大小(注:这里Off ...
- java对象内存大小评估
Java对象的内存布局:对象头(Header).实例数据(Instance Data)和对齐填充(Padding).无论是32位还是64位的HotSpot,使用的都是8字节对齐.也就是说每个java对 ...
- Java对象的大小及应用类型
基础类型数据的大小是固定的,对于非基本类型的java对象,其大小就值得商榷了. 在java中一个空Object对象的大小是8byte,这个大小只是保存堆中没有任何属性的对象的大小,看下面的语 ...
- C++一个类对象的大小计算
计算一个类对象的大小时的规律: 1.空类.单一继承的空类.多重继承的空类所占空间大小为:1(字节,下同): 2.一个类中,虚函数本身.成员函数(包括静态与非静态)和静态数据成员都是不占用类对象的存储空 ...
- 如何查看java对象的大小
有时需要查看java对象占用了多少内存(对象大小),lucene为我们提供了一个很好的工具类,操作简单,如下: int[] s = new int[1024]; System.out.println( ...
- PG数据库空间大小及数据库对象占用空间大小
select pg_size_pretty(pg_database_size('lrisk')); --查询数据库剩余空间 select pg_database.datname,pg_size_pre ...
随机推荐
- Chrome 最小化恢复之后部分黑屏
解决办法:设置->显示高级设置->关闭硬件加速
- 【题解】【CodeForces712C】Memory and De-Evolution
[题目描述] 给定一个边长为xx的正三角形,现在每秒钟你可以改变其中一条边的长度(修改量整数),在改变过程中,每秒钟都需要保证改变后的三角形是合法的,且变成均为正整数. 现在需要最终把三角形改变成边长 ...
- python3和python2共存 django-admin Fatal error in launcher: Unable to create process using ‘"‘
python3和python2共存 django-admin Fatal error in launcher: Unable to create process using ‘"‘ 出现这个 ...
- Java 类加载器及加载Class字节码
参考来源:http://www.cnblogs.com/fingerboy/p/5456371.html java笔记--理解java类加载器以及ClassLoader类 参考来源:htt ...
- Android Studio and Gradle安装心得
安装基于Eclipse 的ADT一段时间,感觉确实有很多功能不足,通过网上资料,决定改向AS. AS下载了最新的2.3版本,它不分64位与32位,网上说有单独版是瞎扯蛋.只要启动不同的EXE就行了. ...
- Windows 下MySQL zip 安装
主要步骤: 1.下载解压到安装的文件夹 2.配置环境路径 3.配置my.ini文件,设置程序路径和数据存储路径 4.以管理员身份启动Mysqld install(提示sevice安装成功) 5.启动M ...
- mongoose 操作 mongodb 笔记 (自己的笔记,自己看的)
mongodb下载/安装 mongoose npm install --save mongoose mongoose 数据库连接 const mongoose = require('mongoos ...
- dhtmlxtree动态加载节点数据的小随笔
最近做了一个这个东西,颇有些感触,随笔记录一下自己的过程. 首先特别感谢:https://blog.csdn.net/cfl20121314/article/details/46852591,对我的帮 ...
- 2星|《10W+走心文案是怎样炼成的》:标题党。实际是台湾创意总监的一些人生感悟和两三个很一般的创意文案
10W+走心文案是怎样炼成的 作者是台湾人,曾在台湾奥美担任创意总监,做过一些广告.本书是他的一些经验介绍. 总体来说是标题党,作者的广告基本是电视广告,跟文案也有关系,估计播放量也很容易过10W+, ...
- (转)基于Metronic的Bootstrap开发框架经验总结(6)--对话框及提示框的处理和优化
http://www.cnblogs.com/wuhuacong/p/4775282.html 在各种Web开发过程中,对话框和提示框的处理是很常见的一种界面处理技术,用得好,可以给用户很好的页面体验 ...