Java中堆和栈的分析

 
1          内存的分配
Think in Java中详细介绍了当程序运行的时候,具体的内存分配。可以分为寄存器、堆栈、堆、静态存储、常量存储、非RAN存储。
下面具体分析一下java中的堆和栈。
 
1.1         两者比较
1. 栈(stack)与堆(heap)都是Java用来在Ram中存放数据的地方。
2. 栈的优势是,存取速度比堆要快,仅次于直接位于CPU中的寄存器。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。另外,栈数据可以共享,详见第3点。堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是,由于要在运行时动态分配内存,存取速度较慢。
3. Java中的数据类型有两种。基本类型(primitive types), 共有8种,即int, short, long, byte, float, double, boolean, char。存在于栈中。另一种是包装类数据,如Integer, String, Double等将相应的基本数据类型包装起来的类。这些类数据全部存在于堆中.
 
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;
关于String str = "abc"的内部工作。Java内部将此语句转化为以下几个步骤:
(1)先定义一个名为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
---------------------
 Package      Class       Count       Cumulative Count      Memory       Cumulative Memory
 -------      -----       -----       ----------------      ------       -----------------
                Total      2 (100.0%)       2 (100.0%)       48 (100.0%)       48 (100.0%)
java.lang    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%)

Report Date: 2007-4-26 15:27:49
结论: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%)
 
Report Date: 2007-4-26 15:29:07
结论: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%)
 
Report Date: 2007-4-26 15:41:50
结论:相同字符串常量,即使在不同语句中被引用,其内存是共用的,"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%)
 
Report Date: 2007-4-26 15:43:45
结论:"123"和"1234"分别生成了各自的字符数组和String对象。两个new String()分别创建一个String对
象。
 
 
做了一个测试,
              long begin = System.currentTimeMillis();
              for(int i = 0;i<100000000;i++){
//String str = "abcdefghijklmnopqrstuvwxyz";
                     String str1 = new String("abcdefghijklmnopqrstuvwxyz");
              }
              long end = System.currentTimeMillis();
             
              System.out.println(end - begin);
 
执行循环一亿次的时候,第一个消耗时间为296毫秒,第二个消耗时间3130毫秒。
采用new String()方式比直接赋值,效率上比第一个慢10倍。从而验证了上面的结论。
 
字符串连接效率比较
              /**
               * 验证 + 和 StringBuffer还有StringBuilder的效率
               */
              int count = 20000;
              String s = "t";
              long begin = System.currentTimeMillis();
              for (int i = 0; i < count; i++) {
                     s += "t"+i;
              }
              long end = System.currentTimeMillis();
              System.out.println(end - begin);
             
             
              StringBuffer sb = new StringBuffer();
              begin = System.currentTimeMillis();
              for (int i = 0; i < count; i++) {
                     sb.append("t"+i);
              }
              end = System.currentTimeMillis();
              System.out.println(end - begin);
             
              StringBuilder sbuild = new StringBuilder();
              begin = System.currentTimeMillis();
              for (int i = 0; i < count; i++) {
                     sbuild.append("t"+i);
              }
              end = System.currentTimeMillis();
              System.out.println(end - begin);
Count = 20000
 
33192
32
0
 
count = 50000
 
556580
62
32
 
 
可以看到当每次连接的字符串不一样的时候,StringBuilder的效率最高,而+操作的效率最低,
 
如果每次连接的字符串相同的话,也是+操作最耗时。
/**
               * 验证 + 和 StringBuffer还有StringBuilder的效率
               */
              int count = 20000;
              String s = "test";
              long begin = System.currentTimeMillis();
              for (int i = 0; i < count; i++) {
                     s += "test";
              }
              long end = System.currentTimeMillis();
              System.out.println(end - begin);
             
             
              StringBuffer sb = new StringBuffer();
              begin = System.currentTimeMillis();
              for (int i = 0; i < count; i++) {
                     sb.append("test");
              }
              end = System.currentTimeMillis();
              System.out.println(end - begin);
             
              StringBuilder sbuild = new StringBuilder();
              begin = System.currentTimeMillis();
              for (int i = 0; i < count; i++) {
                     sbuild.append("test");
              }
              end = System.currentTimeMillis();
              System.out.println(end - begin);
Count = 20000
 
19311
16
0
 
Count = 50000
323140
32
15
 
 
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值