java性能优化 中,如何使用内存管理是一个要优先考虑的因素。谈到内存就必须要提到堆和栈提到堆和栈就必须要提到进程和线程,可能有同学会问:堆和栈有啥区别捏?要说堆和栈的差别,那可相当之大。如果你对这两个概念还是不太明白或者经常混淆,或对进程和线程不太清楚,建议先找本操作系统的书学习学习。

由于是 介绍性能,所以来讨论一下堆和栈在性能方面的差别(这个差异是很大滴)。堆相对进程来说是全局的,能够被所有线程访问;而栈是线程局部的,只能本线程访 问。

同样道理,由于堆是所有线程共有的,从堆里面申请内存要进行相关的加锁操作,因此申请堆内存的复杂度和时间开销比栈要大很多;从栈里面申请内存,虽然又简单又快,但是栈的大小有限,分配不了太多内存。

  ★定义 
   先明确一下什么是基本类型,什么是引用类型。简单地说,所谓基本类型就是Java语言中如下的8种内置类型:booleancharbyte shortintlongfloatdouble。而引用类型就是那些可以通过new来创建对象的类型(基本上都是派生自Object)。
  ★两种类型的存储方式 
  这两种类型的差异,首先体现在存储方式上。
  ◇引用类型的创建
  当你在函数中 创建一个引用类型的对象时,比如下面的语句:
  StringBuffer str = new StringBuffer(); 
  该StringBuffer对象 的内容是存储在堆(Heap)上的,需要申请堆内存。而变量str只不过是针对该StringBuffer对象的一个引用(或者叫地址)。变量str (也就是StringBuffer对象的地址)是存储在栈上的。
  ◇基本类型的创建
  当你在函数中 创建一个基本类型的变量时,比如如下语句:
  int n = 123; 
  这个变量n 也是存储在栈(Stack)上的,但是这个语句不需要再从堆中申请内存了。
 

  ★why do this? 

  可能有同学又问了,干嘛把两种类型分开存储,干嘛不放到一起捏?这个问题问得好!下面我们就来揣测一下,当初Java为啥设计成这样。
  当年 设计java语言的时候,对于这个问题有点进退两难。如果把各种东东都放置到栈中,显然不现实,一来栈是线程私有的(不便于共享),二来栈的大小是有限的,三来栈 的结构也间接限制了它的用途。那为啥不把各种东东都放置到堆里面捏?都放堆里面,倒是能绕过上述问题,但是刚才也提到了,申请堆内存要办很多手续,太繁 琐。如果仅仅在函数中写一个简单的int n = 0; ”,也要到堆里面去分配内存,那性能就大大滴差了(要知道Java1995年生出来的,那年头我家的PC4兆内存就属豪华配置了)。
   左思右想之后,只好做了一个折中:把类型分为基本类型和引用类型,两者使用不同的创建方式。这种差异从Java语法上也可以看出来:引用类 型可以用new创建对象(对于某些单键,表面上没用new,但是在getInstance()内部也还是用的new);而基本类型则不需要用new来创 建。
  ★弊端 
  顺便跑题一下,斗胆评价Java它爹这种设计的弊端(希望Java Fans不要跟我急)。我个人认为:这个折中的决策,带来了许多深远的影响,随手举出几个例子:
  1、由于基本类型不是派生自Object,因此不能算是纯种的对象。这导致了Java 面向对象招牌打了折扣(当年Sun老是吹嘘Java OO的语言)。
  2、由于基本类型不是派生自Object,出于某些场合(比如容器类)的考虑,不得不为每个基本类型加上对应的包装类(比如IntegerByte等),使得语言变得有点冗余。
  ★综合
  从上述的介绍,我们应该知道,使用new创建对象的开销是不小 的。在程序中能避免就应该尽量避免。另外,使用new创建对象,不光是创建时开销大,将来垃圾回收时,销毁对象也是有开销的。