「java计算对象大小」java 大对象
今天给各位分享java计算对象大小的知识,其中也会对java 大对象进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!
本文目录一览:
如何计算java对象的大小
首先,我们先写一段大家可能不怎么写或者认为不可能的代码:一个类中,几个类型都是private类型,没有public方法,如何对这些属性进行读写操作,看似不可能哦,为什么,这违背了面向对象的封装,其实在必要的时候,留一道后门可以使得语言的生产力更加强大,对象的序列化不会因为没有public方法就无法保存成功吧,OK,我们简单写段代码开个头,逐步引入到怎么样去测试对象的大小,一下代码非常简单,相信不用我解释什么:
import java.lang.reflect.Field;
class NodeTest1 {
private int a = 13;
private int b = 21;
}
public class Test001 {
public static void main(String []args) {
NodeTest1 node = new NodeTest1();
Field []fields = NodeTest1.class.getDeclaredFields();
for(Field field : fields) {
field.setAccessible(true);
try {
int i = field.getInt(node);
field.setInt(node, i * 2);
System.out.println(field.getInt(node));
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
代码最基本的意思就是:实例化一个NodeTest1这个类的实例,然后取出两个属性,分别乘以2,然后再输出,相信大家会认为这怎么可能,NodeTest1根本没有public方法,代码就在这里,将代码拷贝回去运行下就OK了,OK,现在不说这些了,运行结果为:
26
42
为什么可以取到,是每个属性都留了一道门,主要是为了自己或者外部接入的方便,相信看代码自己仔细的朋友,应该知道门就在:field.setAccessible(true);代表这个域的访问被打开,好比是一道后门打开了,呵呵,上面的方法如果不设置这个,就直接报错。
看似和对象大小没啥关系,不过这只是抛砖引玉,因为我们首先要拿到对象的属性,才能知道对象的大小,对象如果没有提供public方法我们也要知道它有哪些属性,所以我们后面多半会用到这段类似的代码哦!
对象测量大小的方法关键为java提供的(1.5过后才有):java.lang.instrument.Instrumentation,它提供了丰富的对结构的等各方面的跟踪和对象大小的测量的API(本文只阐述对象大小的测量方法),于是乎我心喜了,不过比较恶心的是它是实例化类:sun.instrument.IntrumentationImpl是sun开头的,这个鬼东西有点不好搞,翻开源码构造方法是private类型,没有任何getInstance的方法,写这个类干嘛?看来这个只能被JVM自己给初始化了,那么怎么将它自己初始化的东西取出来用呢,唯一能想到的就是agent代理,那么我们先抛开代理,首先来写一个简单的对象测量方法:
步骤1:(先创建一个用于测试对象大小的处理类)
import java.lang.instrument.Instrumentation;
public class MySizeOf {
private static Instrumentation inst;
/**
*这个方法必须写,在agent调用时会被启用
*/
public static void premain(String agentArgs, Instrumentation instP) {
inst = instP;
}
/**
* 直接计算当前对象占用空间大小,包括:当前类及超类的基本类型实例字段大小
* 引用类型实例字段引用大小、实例基本类型数组总占用空间、实例引用类型数组引用本身占用空间大小
* 但是不包括超类继承下来的和当前类声明的实例引用字段的对象本身的大小、实例引用数组引用的对象本身的大小
* 用来测量java对象的大小(这里先理解这个大小是正确的,后面再深化)
*/
public static long sizeOf(Object o) {
if(inst == 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 inst.getObjectSize(o);
}
}
步骤2:上面我们写好了agent的代码,此时我们要将上面这个类编译后打包为一个jar文件,并且在其包内部的META-INF/MANIFEST.MF文件中增加一行:Premain-Class: MySizeOf代表执行代理的全名,这里的类名称是没有package的,如果你有package,那么就写全名,我们这里假设打包完的jar包名称为agent.jar(打包过程这里简单阐述,就不细说了),OK,继续向下走:
步骤3:编写测试类,测试类中写:
public class TestSize {
public static void main(String []args) {
System.out.println(MySizeOf.sizeOf(new Integer(1)));
System.out.println(MySizeOf.sizeOf(new String("a")));
System.out.println(MySizeOf.sizeOf(new char[1]));
}
}
如何计算Java对象所占内存的大小
java中可以用.getBytes().length获取字符串占用内容的大小,原理是java中任何字符都采用Unicode编码,所以衡量占用内存大小采用占用的字节数。
举例如下:
public
class
TestStringSize
{
public
static
final
void
main(String[]
args)
{
System.out.println("占用内存大小:"+"学java".getBytes().length);
}
}
输出结果:
占用内存大小:6
byte
怎么确定Java对象的大小
普通对象的结构如下,按64位机器的长度计算
1. 对象头(_mark), 8个字节
2. Oop指针,如果是32G内存以下的,默认开启对象指针压缩,4个字节
3. 数据区
4.Padding(内存对齐),按照8的倍数对齐
数组对象结构是
1. 对象头(_mark), 8个字节
2. Oop指针,如果是32G内存以下的,默认开启对象指针压缩,4个字节
3. 数组长度,4个字节
4. 数据区
5. Padding(内存对齐),按照8的倍数对齐
清楚了对象在内存的基本布局后,咱们说两种计算Java对象大小的方法
1. 通过java.lang.instrument.Instrumentation的getObjectSize(obj)直接获取对象的大小
2. 通过sun.misc.Unsafe对象的objectFieldOffset(field)等方法结合反射来计算对象的大小
java.lang.instrument.Instrumentation.getObjectSize()的方式
先讲讲java.lang.instrument.Instrumentation.getObjectSize()的方式,这种方法得到的是Shallow Size,即遇到引用时,只计算引用的长度,不计算所引用的对象的实际大小。如果要计算所引用对象的实际大小,可以通过递归的方式去计算。
java.lang.instrument.Instrumentation的实例必须通过指定javaagent的方式才能获得,具体的步骤如下:
1. 定义一个类,提供一个premain方法: public static void premain(String agentArgs, Instrumentation instP)
2. 创建META-INF/MANIFEST.MF文件,内容是指定PreMain的类是哪个: Premain-Class: sizeof.ObjectShallowSize
3. 把这个类打成jar,然后用java -javaagent XXXX.jar XXX.main的方式执行
有兴趣可以看下博主的:
java计算对象大小的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于java 大对象、java计算对象大小的信息别忘了在本站进行查找喔。