实现一个sizeof获取Java对象大小.docx

上传人:b****7 文档编号:23469763 上传时间:2023-05-17 格式:DOCX 页数:18 大小:23.06KB
下载 相关 举报
实现一个sizeof获取Java对象大小.docx_第1页
第1页 / 共18页
实现一个sizeof获取Java对象大小.docx_第2页
第2页 / 共18页
实现一个sizeof获取Java对象大小.docx_第3页
第3页 / 共18页
实现一个sizeof获取Java对象大小.docx_第4页
第4页 / 共18页
实现一个sizeof获取Java对象大小.docx_第5页
第5页 / 共18页
点击查看更多>>
下载资源
资源描述

实现一个sizeof获取Java对象大小.docx

《实现一个sizeof获取Java对象大小.docx》由会员分享,可在线阅读,更多相关《实现一个sizeof获取Java对象大小.docx(18页珍藏版)》请在冰豆网上搜索。

实现一个sizeof获取Java对象大小.docx

实现一个sizeof获取Java对象大小

  实现一个sizeof获取Java对象大小

  

在学习编程的过程中,我觉得不止要获得课本的知识,更多的是通过学习技术知识提高解决问题的能力,这样我们才能走在最前方,更多Java学习,请搜索疯狂Java;

  由于Java的设计者不想让程序员管理和了解内存的使用,我们想要知道一个对象在内存中的大小变得比较困难了。

本文提供了可以获取对象的大小的方法,但是由于各个虚拟机在内存使用上可能存在不同,因此该方法不能在各虚拟机上都适用,而是仅在hotspot32位虚拟机上,或者其它内存管理方式与hotspot32位虚拟机相同的虚拟机上适用。

  本方法使用了Unsafe类来访问对象的私有属性,因此有些特殊的设置和做法,要留意类定义前面的文字说明。

  要想计算对象大小,我们必须熟悉hotspot32上不同类型所占的空间:

  一,原始类型primitives:

  boolean:

1byte,尽管Java语言规范里面boolean是一个bit;

  byte:

1byte;

  char:

2bytes;

  short:

2bytes;

  int:

4bytes;

  float:

4bytes;

  long:

8bytes;

  double:

8bytes。

  二,引用类型:

  4bytes,即使是null值也是如此。

  三,空的普通对象(无任何属性,如newObject(),不是null对象):

  8bytes。

存放对象头的各种信息。

  四,空的数组(即长度为0的数组,而不是null数组):

  12bytes,其中比普通对象多出来的4bytes是用来放数组长度的。

  五,hotspot32分配内存是以8bytes的整数倍来计算的,因此不足8个字节的对象要补足剩余的

  字节数以对齐。

  Java代码

  /**

  *这个例子在eclipse里不能直接编译,要到项目的属性,

  *JavaCompiler,Errors/Warnings中DeprecatedandrestrictedAPI

  *中Forbiddenreference(accessrules)中设置为warning。

  *

  *获取一个Java对象在内存所占的空间,不同的虚拟机内存管理方式可能不同,

  *本例是针对32位的hotspot虚拟机的。

  *

  *由于虚拟机对字符串做了特殊处理,比如将其放入常量池,因此sizeof得到的字符串

  *包含了常量池里面占用的空间。

基本类型的包装类也会重复利用对象。

  *

  *设计作者:

teasp

  *信息描述:

  */

  @SuppressWarnings("restriction")

  publicclassHotspotSizeof

  {

  publicstaticfinalintOBJ_BASIC_LEN=8*8;

  publicstaticfinalintARRAY_BASIC_LEN=12*8;

  publicstaticfinalintOBJ_REF_LEN=4*8;

  publicstaticfinalintALIGN=8*8;

  privatestaticUnsafeUNSAFE;

  static{

  try

  {

  FieldtheUnsafe=Unsafe.class.getDeclaredField("theUnsafe");

  theUnsafe.setAccessible(true);

  UNSAFE=(Unsafe)theUnsafe.get(null);

  }

  catch(Exceptione)

  {

  e.printStackTrace();

  }

  }

  /**

  *原始类型的种类,以及每个类型所占空间,单位为bit

  *@authorAdministrator

  *

  */

  privateenumPType

  {

  布尔(8)/*Java语言规定是1个bit*/,字节(8),字符(16),短整(16),

  整形(32),浮点(32),长整(64),双精(64);

  privateintbits;

  privatePType(intbits)

  {

  this.bits=bits;

  }

  publicintgetBits(){

  returnbits;

  }

  }

  /**

  *计算obj对象在虚拟机中所占的内存,单位为bit。

  *如果isPapa为true,则表明计算的是obj对象父类定义的属性。

  *

  *@paramobj

  *@paramclazz

  *@paramisPapa

  *@return

  */

  privatestaticintgetObjBits(Objectobj,Classclazz,booleanisPapa)

  {

  intbits=0;

  if(obj==null)

  {

  returnbits;

  }

  bits+=OBJ_BASIC_LEN;

  if(isPapa)

  {

  bits=0;

  }

  Field[]fields=clazz.getDeclaredFields();

  if(fields!

=null)

  {

  for(Fieldfield:

fields)

  {

  //静态属性不参与计算

  if(Modifier.isStatic(field.getModifiers()))

  {

  //System.out.println("static"+field.getName());

  continue;

  }

  Classc=field.getType();

  if(c==boolean.class)

  {

  bits+=PType.布尔.getBits();

  }

  elseif(c==byte.class)

  {

  bits+=PType.字节.getBits();

  }

  elseif(c==char.class)

  {

  bits+=PType.字符.getBits();

  }

  elseif(c==short.class)

  {

  bits+=PType.短整.getBits();

  }

  elseif(c==int.class)

  {

  bits+=PType.整形.getBits();

  System.out.println(field.getName()+"="+UNSAFE.getInt(obj,

  UNSAFE.objectFieldOffset(field)));

  }

  elseif(c==float.class)

  {

  bits+=PType.浮点.getBits();

  }

  elseif(c==long.class)

  {

  bits+=PType.长整.getBits();

  }

  elseif(c==double.class)

  {

  bits+=PType.双精.getBits();

  }

  elseif(c==void.class)

  {

  //nothing

  }elseif(c.isArray())

  {//是数组

  Objecto=UNSAFE.getObject(obj,UNSAFE.objectFieldOffset

  (field));

  bits+=OBJ_REF_LEN;

  if(o!

=null)

  {

  try

  {

  bits+=bitsofArray(o);

  }catch(Exceptione)

  {

  thrownewRuntimeException(e);

  }

  }

  }else

  {//普通对象

  Objecto=UNSAFE.getObject(obj,UNSAFE.objectFieldOffset

  (field));

  bits+=OBJ_REF_LEN;

  if(o!

=null)

  {

  try

  {

  bits+=bitsof(o);

  }catch(Exceptione)

  {

  thrownewRuntimeException(e);

  }

  }

  }

  }

  }

  Classpapa=clazz.getSuperclass();

  if(papa!

=null)

  {

  bits+=getObjBits(obj,papa,true);

  }

  //补齐,当计算父类属性时,因为是对同一个对象在进行统计,所以不要补齐。

  //一个对象只做一次补齐动作。

  if(false==isPapa)

  {

  if(bits%ALIGN>0)

  {

  bits+=(ALIGN-bits%ALIGN);

  }

  }

  returnbits;

  }

  /**

  *计算arr数组在虚拟机中所占的内存,单位为bit

  *@paramarr

  *@return

  */

  privatestaticintbitsofArray(Objectarr)

  {

  intbits=0;

  if(arr==null)

  {

  returnbits;

  }

  bits+=ARRAY_BASIC_LEN;

  Classc=arr.getClass();

  if(c.isArray()==false)

  {

  thrownewRuntimeException("Mustbearray!

");

  }

  if(c==boolean[].class)

  {

  bits+=PType.布尔.getBits()*((boolean[])arr).length;

  }

  elseif(c==byte[].class)

  {

  bits+=PType.字节.getBits()*((byte[])arr).length;

  }

  elseif(c==char[].class)

  {

  bits+=PType.字符.getBits()*((char[])arr).length;

  }

  elseif(c==short[].class)

  {

  bits+=PType.短整.getBits()*((short[])arr).length;

  }

  elseif(c==int[].class)

  {

  bits+=PType.整形.getBits()*((int[])arr).length;

  }

  elseif(c==float[].class)

  {

  bits+=PType.浮点.getBits()*((float[])arr).length;

  }

  elseif(c==long[].class)

  {

  bits+=PType.长整.getBits()*((long[])arr).length;

  }

  elseif(c==double[].class)

  {

  bits+=PType.双精.getBits()*((double[])arr).length;

  }

  else

  {

  Object[]os=(Object[])arr;

  for(Objecto:

os)

  {

  bits+=OBJ_REF_LEN+bitsof(o);

  }

  }

  //补齐

  if(bits%ALIGN>0)

  {

  bits+=(ALIGN-bits%ALIGN);

  }

  returnbits;

  }

  /**

  *计算obj对象在虚拟机中所占的内存,单位为bit

  *@paramobj

  *@return

  */

  privatestaticintbitsof(Objectobj)

  {

  if(obj==null)

  {

  return0;

  }

  if(obj.getClass().isArray())

  {

  returnbitsofArray(obj);

  }

  returngetObjBits(obj,obj.getClass(),false);

  }

  /**

  *计算obj对象在虚拟机中所占的内存,单位为byte

  *@paramobj

  *@return

  */

  publicstaticintsizeof(Objectobj)

  {

  returnbitsof(obj)/8;

  }

  privatestaticvoidrunGC()throwsException

  {

  //IthelpstocallRuntime.gc()

  //usingseveralmethodcalls:

  for(intr=0;r<4;++r)_runGC();

  }

  privatestaticvoid_runGC()throwsException

  {

  longusedMem1=usedMemory(),usedMem2=Long.MAX_VALUE;

  for(inti=0;(usedMem1

  {

  Runtime.getRuntime().runFinalization();

  Runtime.getRuntime().gc();

  Thread.yield();

  usedMem2=usedMem1;

  usedMem1=usedMemory();

  }

  }

  privatestaticlongusedMemory()

  {

  returnRuntime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory

  ();

  }

  /**

  *本方法在计算String以及原始类型的包装类的时候可能不准。

  *Strings="abc";这种方式产生的String对象会被放入常量池。

  *Integer.valueOf

(1)会返回缓存的对象而不是new一个。

  *@paramcls

  *@return

  *@throwsException

  */

  privatestaticlongdeterminObjSize(Classcls)throwsException

  {

  //Warmupallclasses/methodswewilluse

  runGC();

  usedMemory();

  //Arraytokeepstrongreferencestoallocatedobjects

  finalintcount=100000;

  Object[]objects=newObject[count];

  longheap1=0;

  //Allocatecount+1objects,discardthefirstone

  for(inti=-1;i

  {

  Objectobject=null;

  //Instantiateyourdatahereandassignittoobject

  //object=newObject();

  //object=newInteger(i);

  //object=newLong(i);

  //object=newString();

  //object=newbyte[128][1]

  object=cls.newInstance();

  if(i>=0)

  objects[i]=object;

  else

  {

  object=null;//Discardthewarmupobject

  runGC();

  heap1=usedMemory();//Takeabeforeheapsnapshot

  }

  }

  runGC();

  longheap2=usedMemory();//Takeanafterheapsnapshot:

  finalintsize=Math.round(((float)(heap2-heap1))/count);

  System.out.println("'before'heap:

"+heap1+

  ",'after'heap:

"+heap2);

  System.out.println("heapdelta:

"+(heap2-heap1)+

  ",{"+objects[0].getClass()+"}size="+size+"bytes");

  for(inti=0;i

  objects=null;

  returnsize;

  }

  publicstaticvoidmain(String[]args)

  {

  HotspotSizeofhs=newHotspotSizeof();

  hs.test();

  }

  @Test

  publicvoidtest()

  {

  try

  {

  Assert.assertEquals(determinObjSize(Obj4SizeofTest.class),sizeof(new

  Obj4SizeofTest()));

  }catch(Exceptione)

  {

  thrownewRuntimeException(e);

  }

  }

  }

  测试用的两个类:

  Java代码

  /**

  *设计作者:

teasp

  *信息描述:

  */

  publicclassPapa

  {

  @SuppressWarnings("unused")

  privateintaint=4;

  publicstaticintbint;

  @SuppressWarnings("unused")

  //privateStringstr="123";

  //privateStringstr=newString("123");

  //privateStringstr=newString(newbyte[]{49,50,51});

  privateStringstr=newString(newchar[]{49,50,51});

  @SuppressWarnings("unused")

  privateint[]ints={};

  @SuppressWarnings("unused")

  privateint[][]intss={{}};

  //privateint[][]intss={{1},{1,2}};

  }

  /**

  *设计作者:

teasp

  *信息描述:

  */

  publicclassObj4SizeofTestextendsPapa

  {

  @SuppressWarnings("unused")

  privateintaint=3;

  publicintbint=4;

  @SuppressWarnings("unused")

  privatebooleanb1=true;

  @SuppressWarnings("unused")

  privatebooleanb2=true;

  @SuppressWarnings("unused")

  privatebooleanb3=true;

  @SuppressWarnings("unused")

  privatebooleanb4=true;

  @SuppressWarnings("unused")

  privatebooleanb5=true;

  @SuppressWarnings("unused")

  privatebooleanb6=true;

  @SuppressWarnings("unused")

  privatebooleanb7=true;

  @SuppressWarnings("unused")

  privatebooleanb8=true;

  @SuppressWarnings("unused")

  privateStringstr1;

  @SuppressWarnings("unused")

  privateObjectobj=newPapa();

  publicstaticfinalbyte[]bytes={97};

  @SuppressWarnings("unused")

  privateStringstr2=newString(bytes);

  @SuppressWarnings("unused")

  privateIntegeri=newInteger

(1);

  @SuppressWarnings("unused")

  privateint[]is={1,2,3};

  @SuppressWarnings("unused")

  privateObject[][]o

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 表格模板 > 调查报告

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1