JAVA 内存管理总结
作者:网络转载 发布时间:[ 2014/2/20 9:19:58 ] 推荐标签:JAVA 内存管理 内存泄露
c) 创建多个不同的对象实例
一个类通过使用new运算符可以创建多个不同的对象实例,这些对象实例将在堆中被分配不同的内存空间,改变其中一个对象的状态不会影响其他对象的状态。例如:
Rectangle r1= new Rectangle(3,5);
Rectangle r2= new Rectangle(4,6);
此时,将在堆内存中分别为两个对象的成员变量width、height分配内存空间,两个对象在堆内存中占据的空间是互不相同的。如果有:
Rectangle r1= new Rectangle(3,5);
Rectangle r2=r1;
则在堆内存中只创建了一个对象实例,在栈内存中创建了两个对象引用,两个对象引用同时指向一个对象实例。
d) 包装类
基本型别都有对应的包装类:如int对应Integer类,double对应Double类等,基本类型的定义都是直接在栈中,如果用包装类来创建对象,和普通对象一样了。例如:int i=0;i直接存储在栈中。 Integer i(i此时是对象) = new Integer(5);这样,i对象数据存储在堆中,i的引用存储在栈中,通过栈中的引用来操作对象。
e) String
String是一个特殊的包装类数据。可以用用以下两种方式创建:String str = new String("abc");String str = "abc";
第一种创建方式,和普通对象的的创建过程一样;
第二种创建方式,Java内部将此语句转化为以下几个步骤:
(1) 先定义一个名为str的对String类的对象引用变量:String str;
(2) 在栈中查找有没有存放值为"abc"的地址,如果没有,则开辟一个存放字面值为"abc"
地址,接着创建一个新的String类的对象o,并将o的字符串值指向这个地址,而且在栈
这个地址旁边记下这个引用的对象o。如果已经有了值为"abc"的地址,则查找对象o,并
回o的地址。
(3) 将str指向对象o的地址。
值得注意的是,一般String类中字符串值都是直接存值的。但像String str = "abc";这种
合下,其字符串值却是保存了一个指向存在栈中数据的引用。
为了更好地说明这个问题,我们可以通过以下的几个代码进行验证。
String str1="abc";
String str2="abc";
System.out.println(s1==s2);//true
注意,这里并不用str1.equals(str2);的方式,因为这将比较两个字符串的值是否相等。==号,根据JDK的说明,只有在两个引用都指向了同一个对象时才返回真值。而我们在这里要看的是,str1与str2是否都指向了同一个对象。
我们再接着看以下的代码。
String str1= new String("abc");
String str2="abc";
System.out.println(str1==str2);//false
创建了两个引用。创建了两个对象。两个引用分别指向不同的两个对象。
以上两段代码说明,只要是用new()来新建对象的,都会在堆中创建,而且其字符串是单独存值的,即使与栈中的数据相同,也不会与栈中的数据共享。
f) 数组
当定义一个数组,int x[];或int []x;时,在栈内存中创建一个数组引用,通过该引用(即数组名)来引用数组。x=new int[3];将在堆内存中分配3个保存int型数据的空间,堆内存的首地址放到栈内存中,每个数组元素被初始化为0。
g) 静态变量
用static的修饰的变量和方法,实际上是指定了这些变量和方法在内存中的"固定位置"-static storage,可以理解为所有实例对象共有的内存空间。static变量有点类似于C中的全局变量的概念;静态表示的是内存的共享,是它的每一个实例都指向同一个内存地址。把static拿来,是告诉JVM它是静态的,它的引用(含间接引用)都是指向同一个位置,在那个地方,你把它改了,它不会变成原样,你把它清理了,它不会回来了。 那静态变量与方法是在什么时候初始化的呢?对于两种不同的类属性,static属性与instance属性,初始化的时机是不同的。instance属性在创建实例的时候初始化,static属性在类加载,也是第一次用到这个类的时候初始化,对于后来的实例的创建,不再次进行初始化。 我们常可看到类似以下的例子来说明这个问题:
class Student{
static int numberOfStudents=0;
Student()
{
numberOfStudents++;
}
}
每一次创建一个新的Student实例时,成员numberOfStudents都会不断的递增,并且所有的Student实例都访问同一个numberOfStudents变量,实际上int numberOfStudents变量在内存中只存储在一个位置上。
5. Java的内存管理实例
Java程序的多个部分(方法,变量,对象)驻留在内存中以下两个位置:即堆和栈,现在我们只关心3类事物:实例变量,局部变量和对象:
实例变量和对象驻留在堆上
局部变量驻留在栈上
让我们查看一个java程序,看看他的各部分如何创建并且映射到栈和堆中:
public class Dog {
Collar c;
String name;
//1. main()方法位于栈上
public static void main(String[] args) {
//2. 在栈上创建引用变量d,但Dog对象尚未存在
Dog d;
//3. 创建新的Dog对象,并将其赋予d引用变量
d = new Dog();
//4. 将引用变量的一个副本传递给go()方法
d.go(d);
}
//5. 将go()方法置于栈上,并将dog参数作为局部变量
void go(Dog dog){
//6. 在堆上创建新的Collar对象,并将其赋予Dog的实例变量
c =new Collar();
}
//7.将setName()添加到栈上,并将dogName参数作为其局部变量
void setName(String dogName){
//8. name的实例对象也引用String对象
name=dogName;
}
//9. 程序执行完成后,setName()将会完成并从栈中清除,此时,局部变量dogName也会消失,尽管它所引用的String仍在堆上
}

sales@spasvo.com