第二点解释我的却错了,只要把test1(0)改为二test(2)就可以得出正确结论!!
呵呵 一不小心弄错了
向大家道歉!!!
^_^没事咱就灌水哈^_^!!!
来源:隔叶黄莺 - BlogJava
在C/C++中有sizeof()操作,可轻易获知某个类型或实例占用内存大小,sizeof(int) 或者 sizeof(new TestClass)。可是Java中可没有这么直观的方法可用。
因本人看过不少人写代码总爱写成
List userList = new ArrayList(); //注:声明时即初始化一个空 ArrayList
userList = userDao.getAllUsers(); //注:方法getAllUsers()中会生成一个ArrayList的
上面就造成平白多了一个空的 ArrayList(),创建完后即刻就推向GC处置,我就在想这样一个空的 ArrayList 会占用多少内存,于是找来了 Optimizeit 观察后发现一个空的 ArrayList 要占去 24b 内存。那 Java 中有没有更便的捷的方法呢,于是在网上 google "java sizeof",引出不少话题。
但我觉得比较好的一段代码是 java.sizeOf(http://sourceforge.net/projects/sizeof/),需要JDK1.5以上的版本支持,由它测定的空 ArrayList 所占内存确也是 24b。下载到 SizeOf_0_2_src.zip(其中含SizeOf.jar,其实就一个类 SizeOf),假设解压到 F:\Component Library\java\javasizeof。
用法很简单,直接看它的 README.txt 文件就行,因为只有一个类,方法也不多,全是静态方法,可以使用静态引入,看看就明白,只是现在的 0.2 版本推荐的方法是 sizeOf() 和 deepSizeOf(),而不再是 iterativeSizeOf() 的。
它还提供了一个测试代码 TestSizeOf(可从中学习 SizeOf 的用法),在命令行下,进入到 F:\Component Library\java\javasizeof目录,然后执行
F:\Component Library\java\javasizeof>java -javaagent:SizeOf.jar net.sourceforge.sizeof.test.TestSizeOf
显示结果是:
JAVAGENT: call premain instrumentation for class SizeOf
Starting test...
simple obj: 40.0b
int: 0.0b
long: 0.0b
char: 0.0b
double: 16.0b
boolean: 0.0b
Integer: 0.0b
empty string: 0.0b
not empty string: 0.0b
not empty string: 0.0b
simple obj: 24.0b
simple obj: 40.0b
empty list: 24.0b
10 list: 24.0b
20 list no static: 24.0b
1000 o arr: 816.0b
应该会惊讶一下,为什么会出现那么多 0.0b?为什么要用1.5以上版本的jdk,为什么不是用 -classpath 参数,而是 -javaagent 参数?
我们不妨把 javasizeof 的src目录中源代码导入到 eclipse中(相信大多数人都用这个的),可以看到源代码 TestSizeOf,把 SizeOf.skipFlyweightObject(true) 行注释掉,运行 TestSizeOf。
不小心的话,你应该收到 java.lang.IllegalStateException: Instrumentation is null 的异常,没错这个 SizeOf 用到了 JDK1.5 后新加入的 java.lang.instrument.Instrumentation 接口,所以您需要为 TestSizeOf 设置 VM arguments
-javaagent:"F:\Component Library\java\javasizeof\SizeOf.jar"
(注意到在 SizeOf.jar包中的 META-INF\MANIFEST.MF中有 Premain-Class: net.sourceforge.sizeof.SizeOf,这就是 -javaagent: 所在意的。指向SizeOf.jar的路径中有空格的话一定要用双引号引起来)
运行后结果就是:
JAVAGENT: call premain instrumentation for class SizeOf
Starting test...
simple obj: 40.0b
int: 16.0b
long: 16.0b
char: 16.0b
double: 16.0b
boolean: 16.0b
Integer: 16.0b
empty string: 24.0b
not empty string: 24.0b
not empty string: 24.0b
simple obj: 24.0b
simple obj: 40.0b
empty list: 24.0b
10 list: 24.0b
20 list no static: 24.0b
1000 o arr: 816.0b
对于现在的输出值细细去体会吧,也许不符合您早已形成的较为稳固的想法,或许你发现确实存在出入。
SizeOf_0_2_src.zip包中的 README.txt 中部分内容:
java.SizeOf is a simple java agent what can be used to calculate the memory size
of java objects.
The agent is implemented with the java.lang.instrument introduced with java 5.
Here is a simple howto:
1) use the class SizeOf in your code to test the size of your java object:
//configuration steps
SizeOf.skipStaticField(true);
SizeOf.setMinSizeToLog(10);
//calculate object size
SizeOf.iterativeSizeOf()
2) start the jvm with the argument: -javaagent:/SizeOf.jar
To avoid the dependencies of your code to SizeOf the best use of the agent is in
conjunction with aspect.
四、反射性能:
反射是一种强大的工具,但也存在一些不足。一个主要的缺点是对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这类操作总是慢于只直接执行相同的操作。
下面的程序是字段接入性能测试的一个例子,包括基本的测试方法。每种方法测试字段接入的一种形式 -- accessSame 与同一对象的成员字段协作,accessOther 使用可直接接入的另一对象的字段,accessReflection 使用可通过反射接入的另一对象的字段。在每种情况下,方法执行相同的计算 -- 循环中简单的加/乘顺序。
程序如下:
public int accessSame(int loops) {
m_value = 0;
for (int index = 0; index < loops; index++) {
m_value = (m_value + ADDITIVE_VALUE) *
MULTIPLIER_VALUE;
}
return m_value;
}
public int accessReference(int loops) {
TimingClass timing = new TimingClass();
for (int index = 0; index < loops; index++) {
timing.m_value = (timing.m_value + ADDITIVE_VALUE) *
MULTIPLIER_VALUE;
}
return timing.m_value;
}
public int accessReflection(int loops) throws Exception {
TimingClass timing = new TimingClass();
try {
Field field = TimingClass.class.
getDeclaredField("m_value");
for (int index = 0; index < loops; index++) {
int value = (field.getInt(timing) +
ADDITIVE_VALUE) * MULTIPLIER_VALUE;
field.setInt(timing, value);
}
return timing.m_value;
} catch (Exception ex) {
System.out.println("Error using reflection");
throw ex;
}
}
在上面的例子中,测试程序重复调用每种方法,使用一个大循环数,从而平均多次调用的时间衡量结果。平均值中不包括每种方法第一次调用的时间,因此初始化时间不是结果中的一个因素。下面的图清楚的向我们展示了每种方法字段接入的时间:
图 1:字段接入时间 :
我们可以看出:在前两副图中(Sun JVM),使用反射的执行时间超过使用直接接入的1000倍以上。通过比较,IBM JVM可能稍好一些,但反射方法仍旧需要比其它方法长700倍以上的时间。任何JVM上其它两种方法之间时间方面无任何显著差异,但IBM JVM几乎比Sun JVM快一倍。最有可能的是这种差异反映了Sun Hot Spot JVM的专业优化,它在简单基准方面表现得很糟糕。反射性能是Sun开发1.4 JVM时关注的一个方面,它在反射方法调用结果中显示。在这类操作的性能方面,Sun 1.4.1 JVM显示了比1.3.1版本很大的改进。
如果为为创建使用反射的对象编写了类似的计时测试程序,我们会发现这种情况下的差异不象字段和方法调用情况下那么显著。使用newInstance()调用创建一个简单的java.lang.Object实例耗用的时间大约是在Sun 1.3.1 JVM上使用new Object()的12倍,是在IBM 1.4.0 JVM的四倍,只是Sun 1.4.1 JVM上的两部。使用Array.newInstance(type, size)创建一个数组耗用的时间是任何测试的JVM上使用new type[size]的两倍,随着数组大小的增加,差异逐步缩小。
结束语:
Java语言反射提供一种动态链接程序组件的多功能方法。它允许程序创建和控制任何类的对象(根据安全性限制),无需提前硬编码目标类。这些特性使得反射特别适用于创建以非常普通的方式与对象协作的库。例如,反射经常在持续存储对象为数据库、XML或其它外部格式的框架中使用。Java reflection 非常有用,它使类和数据结构能按名称动态检索相关信息,并允许在运行着的程序中操作这些信息。Java 的这一特性非常强大,并且是其它一些常用语言,如 C、C++、Fortran 或者 Pascal 等都不具备的。
但反射有两个缺点。第一个是性能问题。用于字段和方法接入时反射要远慢于直接代码。性能问题的程度取决于程序中是如何使用反射的。如果它作为程序运行中相对很少涉及的部分,缓慢的性能将不会是一个问题。即使测试中最坏情况下的计时图显示的反射操作只耗用几微秒。仅反射在性能关键的应用的核心逻辑中使用时性能问题才变得至关重要。
许多应用中更严重的一个缺点是使用反射会模糊程序内部实际要发生的事情。程序人员希望在源代码中看到程序的逻辑,反射等绕过了源代码的技术会带来维护问题。反射代码比相应的直接代码更复杂,正如性能比较的代码实例中看到的一样。解决这些问题的最佳方案是保守地使用反射——仅在它可以真正增加灵活性的地方——记录其在目标类中的使用。
对于测试结果:
我运行后产生的
JAVAGENT: call premain instrumentation for class SizeOf
Starting test...
simple obj: 776.0b
int: 16.0b
long: 16.0b
char: 16.0b
double: 176.0b
boolean: 16.0b
Integer: 16.0b
empty string: 24.0b
not empty string: 24.0b
not empty string: 24.0b
simple obj: 24.0b
simple obj: 776.0b
empty list: 24.0b
10 list: 24.0b
20 list no static: 24.0b
1000 o arr: 816.0b
[此贴子已经被作者于2007-10-11 11:26:30编辑过]