打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
计算Java Serializable对象大小的方法
在Cahce的设计中,一般会考虑两种对象管理方法,一是按对象大小,比如开一个10M字节的cahce空间。另外一个是按对象的数量,比如1000个对象的cache空间。
对于按对象尺寸管理的cache,由于Java对象的实际内存大小不好获得(我是不知道如何计算的),所以一般就使用一个Serializable对象的序列化尺寸来代替,序列化时通常把一个对象序列化到一个字节buffer里,那么就可以获得这个buffer的字节数。今天,在工作中,突软想到这样做太浪费空间,看了Java的ObjectOutputStream这个类的源码,发现也可以如下做,只计数,不产生字节转移,那么就不会耗费内存空间了。
Java代码 
 
public final class SizeCalculator {
public static int calcSize(java.io.Serializable o) {
int ret = 0;
class DumbOutputStream extends OutputStream {
int count = 0;
public void write(int b) throws IOException {
count++; // 只计数,不产生字节转移
}
}
DumbOutputStream buf = new DumbOutputStream();
ObjectOutputStream os = null;
try {
os = new ObjectOutputStream(buf);
os.writeObject(o);
ret = buf.count;
} catch (IOException e) {
// No need handle this exception
e.printStackTrace();
ret = -1;
} finally {
try {
os.close();
} catch (Exception e) {
}
}
return ret;
}
public static void main(String[] args){
System.err.println(calcSize(1));
}
============================
Java对象在内存中的形态跟序列化后的形态占的空间大小没有必然联系诶。
用行为良好的Java代码来实现序列化,在任何符合JVM规范的环境中对同样的Java对象做序列化得到的都应该是一样的结果。然而在不同的JVM实现中,对象布局是不一样的,甚至在一些实现了automatic object inlining的JVM中对象布局还可以应需调整。
除了对象布局外,数据本身的保存方式也可能有出入。例如字符串,如果某个JVM内部是用UTF-16来保存而某中序列化方式采用UTF-8来保存,那么同一字符串占的空间就可能有差异。
比较靠谱的办法是通过JVMTI来获取Java对象大小。可以参考这篇文章里实现的一个JVMTI agent,它实现了单个对象的sizeOf()与某个对象及其所引用的所有对象的fullSizeOf()。
以前有一帖提到了在Sun的JRE 1.6.0 update 14的HotSpot VM中某些数组对象在内存中的布局,有兴趣的话也可以看看。==========================
/**
*Name: Sizeof.java
*Copyright: zhaozhihua
*
*/
package com.boco.gdau.util;
/**
* Description:
* <p>Change Log:
* <p>2010-2-4 create by zhaozhihua
* <p>
* @version 1.0
* @date 2010-2-4
* @author zhaozhihua
*/
import java.io.PrintStream;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Stack;
/*+*********************************************************************
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation
Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
************************************************************************/
/**
* <p>estimator for the size of data structures. The sizes of
* individual elements used to compute the overall size of a data
* structure are estimates only derived on 1.4.2 on a 32bit Linux.</p>
*
* <p>The implementation will be changed to
* <code>java.lang.instrument.Instrumentation</code> as soon as we
* switch to Java 5.</p>
*
* @author &copy; 2005 Harald Kirsch
*/
public class Sizeof {
// no need for this to show up in the docs
private Sizeof() {}
static final Hashtable pSizes;
static {
pSizes = new Hashtable();
pSizes.put(Boolean.TYPE, new Integer(1));
pSizes.put(Character.TYPE, new Integer(2));
pSizes.put(Byte.TYPE, new Integer(1));
pSizes.put(Short.TYPE, new Integer(2));
pSizes.put(Integer.TYPE, new Integer(4));
pSizes.put(Long.TYPE, new Integer(8));
pSizes.put(Float.TYPE, new Integer(4));
pSizes.put(Double.TYPE, new Integer(8));
pSizes.put(Void.TYPE, new Integer(1));
}
private static final class Root {}
private static void sizeof(Object obj, IdentityHashMap known,
Hashtable types)
{
// The stack always contains a parent class and an object. The
// parent class may be null
Stack stack = new Stack();
stack.push(new Root().getClass());
stack.push(obj);
int rounds = 0;
while( !stack.empty() ) {
Object o = stack.pop();
Object parentClass = stack.pop();
known.put(o, o);
rounds += 1;
if( rounds%100000==0 ) {
System.err.println("rounds: "+rounds+", stacksize:"+stack.size());
}
int size = 8;
Class oc = o.getClass();
// arrays need totally different handling
if( oc.isArray() ) {
// arrays seem to have a minimum size of 16
size += 8;
int alen = Array.getLength(o);
Class ec = oc.getComponentType();
Integer l = (Integer)pSizes.get(ec);
if( l!=null ) {
// array of primitive types
size = size + alen*l.intValue();
} else {
size = size + 4*alen;
Object[] oa = (Object[])o;
for(int i=0; i<alen; i++) {
Object child = oa[i];
if( child!=null && !known.containsKey(child) ) {
// don't use arrays as parents (does not tell a lot)
stack.push(parentClass);
stack.push(child);
}
}
}
} else {
// handle o not being an array
// iterate up the inheritance hierarchy
Class c = oc;
while( c!=null ) {
Field[] fields = c.getDeclaredFields();
for(int i=0; i<fields.length; i++) {
Field f = fields[i];
if( Modifier.isStatic(f.getModifiers()) ) continue;
Class fc = f.getType();
// take care of primitive types
// FIX ME: this disregards alignment issues
Integer l = (Integer)pSizes.get(fc);
if( l!=null ) {
size+=l.longValue();
continue;
}
size+=4;
Object child;
f.setAccessible(true);
try {
child = f.get(o);
if( child==null || known.containsKey(child) ) continue;
stack.push(oc);   // should this rather be c?
stack.push(child);
//System.out.println(""+fc+" in "+c);
} catch( IllegalAccessException e ) {
System.err.println("cannot access "+f+" in "+oc);
}
}
c = c.getSuperclass();
}
}
Map parents = (Map)types.get(oc);
if( parents==null ) types.put(oc, parents=new HashMap());
Pair p = (Pair)parents.get(parentClass);
if( p==null ) {
p = new Pair();
parents.put(parentClass, p);
}
p.count +=1 ;
p.size += size;
}//while stack not empty
}
/**********************************************************************/
/**
* recursively delves into the object graph <code>o</code> and
* returns a <code>Hashtable</code> with information about object
* sizes and counts. The keys used in the result are
* <code>java.lang.Class</code> objects.
* Each key <em>k</em> is mapped to a <code>java.util.Map</code>
* object which pairs a class object <em>r</em> and a {@link
* Sizeof.Pair}. The <code>Pair</code> describes how often
* <em>k</em> appears as a field in an object of type <em>r</em>. In
* other words: within the object graph, objects of type <em>r</em>
* are parents of objects of type <em>k</em>.</p>
*/
public static Hashtable sizeof(Object o) {
Hashtable types = new Hashtable();
sizeof(o, new IdentityHashMap(), types);
return types;
}
/**
* prints the result produced with {@link #sizeof sizeof()}.
*/
public static void printTypes(PrintStream out, Hashtable types) {
Enumeration it = types.keys();
long count=0, size=0;
while( it.hasMoreElements() ) {
Class c = (Class)it.nextElement();
Map parents = (Map)types.get(c);
Iterator pit = parents.keySet().iterator();
while( pit.hasNext() ) {
Class parenClass = (Class)pit.next();
Pair p = (Pair)parents.get(parenClass);
String pname = parenClass.getName();
out.println(""+p.count+" "+p.size+" "+c.getName()+" "+pname);
count += p.count;
size += p.size;
}
}
out.println(""+count+" "+size+ " TOTAL");
}
/**********************************************************************/
/**
* a pair of count and size describing use and size of a data type.
*/
public static class Pair {
/**
* number of objects of a certain type.
*/
public int count;
/**
* accumulated size of objects counted.
*/
public long size;
}
public static void main(String[] argv){
int o=1;
Hashtable types = sizeof(o);
printTypes(System.out, types);
}
}
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Java语言与Generics
Java泛型编程快速入门
基于Java回顾之集合的总结概述
java基础有关的面试题
Java笔记(五 数组 对象的克隆 封装类 Class类 Runtime类和Process类 设计模式)
带你领略 Google Collections
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服