JR 精品文章 - Java堆和栈 & StringBuilder效率探究
AD: jr (at) javaresearch.org


首页 | 动态 | 文章 | FAQ  | 新闻 | 下载 | 代码 | 工作 | 调查 | 术语 | 站点 | 图书 | 论坛 | 帮助 | 全部  

TOP | 交流 | 软件 | 专栏 | 开源 | 译/著 | 源码 | API  | 推荐 | FTP  | 积分 | 统计 | 搜索 | Blog | 我们  
首页 » 研究文集 » Java语言深入 搜索标题相关文章 搜索标题相关文章    评论此文章 发表评论     开始监控此文章 开始监控   加入收藏夹  加入收藏夹
Java堆和栈 & StringBuilder效率探究
red-vampire 原创   更新:2008-05-06 13:43:17  版本: 1.0   

对象的创建(即内存的分配 )

    
Thinking in Java中详细介绍了当程序运行的时候,具体的内存分配。 

可以分为寄存器、堆栈、堆、常量存储、非RAM存储。 

下面具体分析一下java中的堆和栈(参考:http://blog.csdn.net/tanghw/archive/2005/02/18/291811.aspx)。 

1.   两者比较
1). 栈(stack)与堆(heap)都是Java用来在RAM中存放数据的地方。 

栈的优势是,存取速度比堆要快,仅次于直接位于CPU中的寄存器。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。另外,栈数据可以共 享,详见第3点。堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是,由于要 在运行时动态分配内存,存取速度较慢。 

2). Java中的数据类型有两种。基本类型(primitive types), 共有8种,即int, short, long, byte, float, double, boolean, char。存在于栈中。另一种是包装类数据,如Integer, String, Double等将相应的基本数据类型包装起来的类。这些类数据全部存在于堆中. 

2.   String处理
String str = "abc";和String str = new String("abc");和char[] c = {'a','b','c'};String str=new String(c);都采用堆存储 

String str = "abc";在栈中如果没有存放值为"abc"的地址,等同于:
String temp=new String("abc");
String str=temp; 

1). 关于String str = "abc"的内部工作。Java内部将此语句转化为以下几个步骤:先定义一个名为str的对String类的对象引用变量:String str; 

2). 在栈中查找有没有存放值为"abc"的地址,如果没有,则开辟一个存放字面值为"abc"的地址,接着创建一个新的String类的对象o,并将o的字符 串值指向这个地址,而且在栈中这个地址旁边记下这个引用的对象o。如果已经有了值为"abc"的地址,则查找对象o,并返回o的地址。 

3). 将str指向对象o的地址。 

使用String str = "abc";的方式,可以在一定程度上提高程序的运行速度,因为JVM会自动根据栈中数据的实际情况来决定是否有必要创建新对象。而对于String str = new String("abc");的代码,则一概在堆中创建新对象,而不管其字符串值是否相等,是否有必要创建新对象,从而加重了程序的负担。 

char[] c = {'a','b','c'};String str=new String(c); 
等同于 

String str = new String('a'+'b'+'c');  

  
1. 

class Test {
public static void main(String[] args) {
    String s = "123";





Runtime Heap Summary: Test
========================== 

Runtime Instance List
--------------------- 

Packag    Class              Count      Cumulative     Count      Memory  Cumulative     Memory

Total                2 (100.0%)       2 (100.0%)        48 (100.0%)       48 (100.0%)
         String      1  (50.0%)       1  (50.0%)        24  (50.0%)       24  (50.0%)
          char[ ]      1  (50.0%)       1  (50.0%)       24  (50.0%)       24  (50.0%)



  
结论:String s = "123",会创建一个"123"字符数组和一个String对象。 

2. 

class Test {
public static void main(String[] args) {
  String s = new String("123"); 






Runtime Heap Summary: Test
========================== 

Runtime Instance List
--------------------- 

 Package      Class       Count       Cumulative Count      Memory       Cumulative Memory
 -------      -----       -----       ----------------      ------       -----------------
                Total      3 (100.0%)       3 (100.0%)       72 (100.0%)       72 (100.0%)
java.lang    String     2  (66.7%)       2  (66.7%)       48  (66.7%)       48  (66.7%)
                char[ ]    1  (33.3%)       1  (33.3%)       24  (33.3%)       24  (33.3%) 

结论:String s = new String("123");根据上面的测试可以看出,"123"创建了一个数组,一个String对象,而new String()又根据"123"对象作为参数,重新生成了一个新的String对象,此对象被s变量引用。 

3. 


class Test {
  public static void main(String[] args) {
    String s1 = "123";
    String s2 = "123";
    if (s1 == s2) {
      System.out.println("s1==s2");
    } else {
      System.out.println("s1!=s2");
    }
  }



输出结果:s1==s2 

4. 


class Test {
  public static void main(String[] args) {
   String s1 = new String("123");
   String s2 = new String("123");
   if (s1 == s2) {
     System.out.println("s1==s2");
   } else {
     System.out.println("s1!=s2");
   }
  }



结果:s1!=s2 

  
5. 

class Test {
public static void main(String[] args) {
  String s1 = new String("123");
  String s2 = new String("123");




Runtime Heap Summary: Test
========================== 

Runtime Instance List
--------------------- 

 Package      Class       Count       Cumulative Count      Memory       Cumulative Memory
 -------      -----       -----       ----------------      ------       -----------------
                Total      4 (100.0%)       4 (100.0%)       96 (100.0%)       96 (100.0%)
java.lang    String     3  (75.0%)       3  (75.0%)       72  (75.0%)       72  (75.0%)
                char[ ]    1  (25.0%)       1  (25.0%)       24  (25.0%)       24  (25.0%) 


结论:相同字符串常量,即使在不同语句中被引用,其内存是共用的,"123"只生成一个字符数据和一个 

String对象,两个new String()分别生成了一个对象。 


6. 

class Test 
{
public static void main(String[] args) 
{
String s1 = new String("123");
String s2 = new String("1234");
}


Runtime Heap Summary: Test
========================== 

Runtime Instance List
--------------------- 

 Package      Class       Count       Cumulative Count       Memory       Cumulative Memory
 -------      -----       -----       ----------------       ------       -----------------
           Total       6 (100.0%)       6 (100.0%)       144 (100.0%)      144 (100.0%)
java.lang     String     4  (66.7%)       4  (66.7%)        96  (66.7%)       96  (66.7%)
                 char[ ]    2  (33.3%)       2  (33.3%)        48  (33.3%)       48  (33.3%) 



结论:"123"和"1234"分别生成了各自的字符数组和String对象。两个new String()分别创建一个String对象。 

做了一个测试, 

              long begin = System.nanoTime();               

//String str = "abcdefghijklmnopqrstuvwxyz"; 

                     String str1 = new String("abcdefghijklmnopqrstuvwxyz");                

              long end = System.nanoTime();               

              System.out.println(end - begin); 

  
创建str对象的时间是: 6426纳秒,创建str1的时间是:29334纳秒 

采用new String()方式比直接赋值,效率上比第一个慢5~10倍(视机器配置)。从而验证了上面的结论。 

  

字符串连接效率比较 

              /** 

               * 验证 + 和 StringBuffer还有StringBuilder的效率 

               */ 

              int count = 50; 

              String s = "t"; 

              long begin = System.nanoTime(); 

              for (int i = 0; i < count; i++) { 

                     s += "t"+i; 

              } 

              long end = System.nanoTime(); 

              System.out.println(end - begin); 

              

              StringBuffer sb = new StringBuffer(); 

              begin = System.nanoTime(); 

              for (int i = 0; i < count; i++) { 

                     sb.append("t"+i); 

              } 

              end = System.nanoTime(); 

              System.out.println(end - begin); 

              

              StringBuilder sbuild = new StringBuilder(); 

              begin = System.nanoTime(); 

              for (int i = 0; i < count; i++) { 

                     sbuild.append("t"+i); 

              } 

              end = System.nanoTime(); 

              System.out.println(end - begin); 
/* Output:

233828
131022
120686  

  

可以看到当每次连接的字符串不一样的时候,StringBuilder的效率最高,而+操作的效率最低, 

如果每次连接的字符串相同的话,也是+操作最耗时。 

/** 

               * 验证 + 和 StringBuffer还有StringBuilder的效率 

               */ 

              int count = 20; 

              String s = "test"; 

              long begin = System.nanoTime(); 

              for (int i = 0; i < count; i++) { 

                     s += "test"; 

              } 

              long end = System.nanoTime(); 

              System.out.println(end - begin); 

              

              StringBuffer sb = new StringBuffer(); 

              begin = System.nanoTime(); 

              for (int i = 0; i < count; i++) { 

                     sb.append("test"); 

              } 

              end = System.nanoTime(); 

              System.out.println(end - begin); 

              

              StringBuilder sbuild = new StringBuilder(); 

              begin = System.nanoTime(); 

              for (int i = 0; i < count; i++) { 

                     sbuild.append("test"); 

              } 

              end = System.nanoTime(); 

              System.out.println(end - begin);
              
/* Output:

116495
20394
19276






版权声明   给作者写信
本篇文章对您是否有帮助?  投票:         投票结果:     11       1
作者其它文章: 作者全部文章
评论人:guoliang 发表时间: Tue May 06 18:17:53 CST 2008
好文章,好用
评论人:yg84 发表时间: Wed May 07 09:46:09 CST 2008
很有帮助
评论人:bluemaple_00 发表时间: Wed May 14 10:12:57 CST 2008
good
collection~~~~~~~~~~~~~~
评论人:lieanzhou 发表时间: Wed May 14 12:26:05 CST 2008
好文章!但是现在看不懂![:E][:E][good]

这个文章共有 4 条评论
主题: 利用反射实现类的动态加载 上一篇文章
返回文章列表 返回〔Java语言深入〕
下一篇文章 主题: 从算法开始提高效率


文字广告链接
        自主、快速定制基于JAVA的B/S业务系统          重量级企业在线自定义WEB报表平台
        Excel制表、零代码发布、打印、图表结合——快逸报表,免费、稳定、功能强大的java工具
        技术圈: 关于Java、dotNet、PHP、Ruby、奇客、Web2.0等更多资讯博客精选文章

关于 JR  |  版权声明  |  联系我们 

©2002-2006 JR 版权所有 沪ICP备05019622号