你知道数据大小吗?--不要花太多的功夫来隐藏类的成员(二)

原创 2003年05月22日 08:29:00
 

结果:<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

让我们来对一些类使用这个工具,察看是否结果和我们预想的一样。

注意:以下的结果都是基于Windows平台的jdk1.3.1版本,并不能保证所有的平台或者jdk版本都得到相同的信息。

l         java.lang.Object

这个所有对象的基类作为我们的第一个例子。对于java.lang.Object我们将得到:

'before' heap: 510696, 'after' heap: 1310696

heap delta: 800000, {class java.lang.Object} size = 8 bytes

所以,一个简单的Object对象要占用8个字节的内存空间,当然我们不能希望它所占的空间是0,因为每个实例都至少必须包含一些最基本的操作,比如equals(), hashCode(), wait()/notify()等。

 

l         java.lang.Integer

我和我的同事都经常封装本地的intInteger的实例中去,以便于我们能在集合的对象中使用它们,那样做到底要耗费多少内存呢?

'before' heap: 510696, 'after' heap: 2110696

heap delta: 1600000, {class java.lang.Integer} size = 16 bytes

这个16字节的结果比我们预想的要糟糕,因为一个int值恰好是4个字节,但是使用了Integer以后,多使用了3倍的空间。

 

l         java.lang.Long

Long看起来应该比Integer使用更多的空间,可是事实并非如此:

'before' heap: 510696, 'after' heap: 2110696

heap delta: 1600000, {class java.lang.Long} size = 16 bytes

很明显,因为一种特别的JVM实现必须符合特定的CPU类型,所以事实上的对象大小在堆中所占的空间必须和低级的内存边界对齐。看起来一个Long是一个8字节的大小的Object对象加上8字节用来保存long值。相比之下,Integer就有4个字节没有使用的空间。所以,应该是JVM强制对象使用8字节作为字的边界。

 

l         Arrays

接下来比较一些基本类型的数组,比较有指导意义,能够部分的发现一些隐藏的信息和证明另一些流行的诡计:使用一个size-1的数组封装基本类型来当作对象。通过修改Sizeof.main()来使用一个循环增加数组的长度。然后能够得到int数组:

length: 0, {class [I} size = 16 bytes

length: 1, {class [I} size = 16 bytes

length: 2, {class [I} size = 24 bytes

length: 3, {class [I} size = 24 bytes

length: 4, {class [I} size = 32 bytes

length: 5, {class [I} size = 32 bytes

length: 6, {class [I} size = 40 bytes

length: 7, {class [I} size = 40 bytes

length: 8, {class [I} size = 48 bytes

length: 9, {class [I} size = 48 bytes

length: 10, {class [I} size = 56 bytes

还有一些char数组:

length: 0, {class [C} size = 16 bytes

length: 1, {class [C} size = 16 bytes

length: 2, {class [C} size = 16 bytes

length: 3, {class [C} size = 24 bytes

length: 4, {class [C} size = 24 bytes

length: 5, {class [C} size = 24 bytes

length: 6, {class [C} size = 24 bytes

length: 7, {class [C} size = 32 bytes

length: 8, {class [C} size = 32 bytes

length: 9, {class [C} size = 32 bytes

length: 10, {class [C} size = 32 bytes

从以上可以看出,8个字节的边界很明显的表现出来了。同时,肯定包含不可避免的8个字节的Object头部,然后基本数据类型的数组占用其它的8个字节。使用int[1]Integer相比,看起来不能提供任何的内存使用,除了可以作为一个同样数据的可变版本。

 

l         多维数组

多维数组有另外的一个惊人之处。开发者普遍的使用一个构造函数例如int[dim1][dim2]用于数字或者科学计算。在一个int[dim1][dim2]的数组实例中,每一个嵌套的int[dim2]都是一个对象,并且每一个对象都加上一个16字节的数组对象头。当我不需要一个三角的或者粗糙的数组,那个代表着纯粹的头部。当维数增加时,影响增加很大。举例来说,一个int[128][2]的实例占用3600字节,使用着246%的头部。在特别的例子byte[256][1]中,这个头部因素已经是19!和C/C++的解决方案相比,同样的语法不会增加这么多的内存消耗。

 

l         java.lang.String

让我们来测试一个空串,现构造一个new String()

'before' heap: 510696, 'after' heap: 4510696

heap delta: 4000000, {class java.lang.String} size = 40 bytes

结果提供了一种相当不好的现象,就是一个空的String就要占用40字节的大小,足够用来保存20个字符了。

在我们使用包含内容的字符串以前,我们使用一个帮组方法来创建一个字符串。不过使用以下文字来创建:

object = "string with 20 chars";

将不会工作,因为所有的这样的对象操作将结束于同一个字符串实例。语言规范中明确表明如此的行为(java.lang.String.intern()),因此使用如下:

    public static String createString (final int length)

    {

        char [] result = new char [length];

        for (int i = 0; i < length; ++ i) result [i] = (char) i;

       

        return new String (result);

    }

 

在这样的创建函数以后,得到如此的结果:

length: 0, {class java.lang.String} size = 40 bytes

length: 1, {class java.lang.String} size = 40 bytes

length: 2, {class java.lang.String} size = 40 bytes

length: 3, {class java.lang.String} size = 48 bytes

length: 4, {class java.lang.String} size = 48 bytes

length: 5, {class java.lang.String} size = 48 bytes

length: 6, {class java.lang.String} size = 48 bytes

length: 7, {class java.lang.String} size = 56 bytes

length: 8, {class java.lang.String} size = 56 bytes

length: 9, {class java.lang.String} size = 56 bytes

length: 10, {class java.lang.String} size = 56 bytes

结果很明显的表明了字符串的内存增加轨迹。但是字符串要增加一个24字节的头部。对于非空的字符串,如果字符个数少于10个或者更少,这个增加的头部将消耗相对于有效的负载(2个字节对于每个字符,加上4个作为长度)在100%400%之间变化。

你知道数据大小吗?--不要花太多的功夫来隐藏类的成员

  • zgqtxwd
  • zgqtxwd
  • 2008年04月25日 15:57
  • 91

你知道数据大小吗?--不要花太多的功夫来隐藏类的成员(三)

 我们能做点什么呢?“这很好,但是我们没有任何选择除了使用String和其它Java提供的类型,是不是这样呢?”我听到你们再问,那么让我们来找找答案吧。 l         封装类封装类比如java....
  • copyright
  • copyright
  • 2003年05月22日 08:29
  • 1183

你知道数据大小吗?--不要花太多的功夫来隐藏类的成员(一)

 你知道数据大小吗?--不要花太多的功夫来隐藏类的成员 摘要:过去很多年里面,许多的Java开发人员都一直在问一个问题:“一个Java对象到底耗费多少内存呢?”在本文中,Vladimir Roubts...
  • copyright
  • copyright
  • 2003年05月22日 08:29
  • 1231

c++中类没有数据成员时,类对象的大小

class X { }; class Y : public virtual X { }; class Z : public virtual X { }; class A : ...
  • wly_2014
  • wly_2014
  • 2016年04月08日 09:50
  • 904

你知道数据大小吗?

google_ad_client = "pub-8800625213955058";/* 336x280, 创建于 07-11-21 */google_ad_slot = "0989131976";...
  • java169
  • java169
  • 2008年05月24日 01:12
  • 147

你所知道的设计模式有哪些?我来给你讲常用的

你所知道的设计模式有哪些 Java中一般认为有23 种设计模式,我们不需要所有的都会,但是其中常用的几种设计模式应该去掌握。下面列出了所有的设计模式。需要掌握的设计模式我单独列出来了,当然能掌握的越多...
  • LiuHai2014csd
  • LiuHai2014csd
  • 2017年03月05日 15:52
  • 2408

C#继承之隐藏基类方法

C#继承之隐藏基类方法或其他信息 当我们在定义一个类并继承了其它类的时候,在派生类中是没有办法删除基类的任何成员,就像我们不能改变父母的基因一样,所能做的只能采用隐藏父类方法,也就像使基因变为隐...
  • giswhw66
  • giswhw66
  • 2017年03月22日 23:10
  • 712

C#中New关键字的三种用法

三种用法如下:   在 C# 中,new 关键字可用作运算符、修饰符或约束。   1)new 运算符:用于创建对象和调用构造函数。这种大家都比较熟悉,没什么好说的了。   2)new...
  • sibaison
  • sibaison
  • 2017年03月26日 17:28
  • 123

NYOJ759 你知道这个规律吗

思路: 模拟除法 如1256/9 12%9=3 35%9=8 86%9=5 (吐槽:这次数组开小了是TL 真心无语) 你知道这个规律吗? 时间限制:1000 ms  |  内存...
  • u012349696
  • u012349696
  • 2014年01月09日 09:41
  • 520

NYOJ 874 签到

 签到 时间限制:1000 ms  |  内存限制:65535 KB 难度:0 描述 你在NYOJ签过到吗?你知道签到可以获得多少OJ币吗?下面就请你来算一下吧。 输入多...
  • zwj1452267376
  • zwj1452267376
  • 2015年10月23日 12:55
  • 346
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:你知道数据大小吗?--不要花太多的功夫来隐藏类的成员(二)
举报原因:
原因补充:

(最多只允许输入30个字)