网上好多答案都说区别在于堆是动态的,栈是静态的。说这种说放可能主要是由于栈分配内存时已经知道了变量占用的内存空间,而堆给对象分配内存大小不是固定的。
先说说栈的作用:
首先栈通常是与线程息息相关的,当一个线程运行时,就会给该线程分配一个对象的栈空间(多个线程会分配多个栈空间,因此如果方法中都是局部变量的话,多线程之间是互不干扰的,如果是含有操作成员变量的话,可能就需要考虑资源同步的问题了),当线程执行某个方法时,会将该方法的传入的参数存入栈中,当方法中创建基本类型的局部变量时,局部变量会放到栈中,当方法中创建对象时,会先去方法区查找响应的class信息,如果没有会去现加载class信息到方法区,对象的引用会放到栈中,类的实例对象会放到堆中。
栈的优点是访问速度快,缺点是栈中的数据大小和声明周期是固定的。
堆的优点是大小是动态分配的。生命周期也不是固定的。缺点就是访问速度慢。
同时栈还有一个特点就是同一个线程对应的栈的数据是共享的。
如:int a = 1;
int b = 1;
上面创建了2个局部变量,执行时会先创建一个a的引用,该引用是存放到栈中的。然后看栈中是否有1的字面值,如果没有就在栈中开辟个空间生成字面值1.a的引用存放的是指向字面值1的地址。接着执行创建引用b,同理b也是存在栈中的。然后检查栈中是否存在为1的字面值,发现存在,因此b引用存放的也是执行字面值1的地址。因此a==b返回true。
接着再说一个特例String
实例1
String a = "abc";
执行时先将引用a存放到栈中,然后检查栈中是否有字面值为"abc"。发现没有则创建一个“abc”的字面值,然后创建一个新的String对象t,然后这个t对象的字符串值存放的是指向“abc”字面值的地址。然后“abc”字面值再加上一个标识指向对象t。最后引用a存放的是执行t堆内存的地址。
如果此时再执行一个String b = "abc";则会先在栈中存放一个b引用,然后检查栈中是否有“abc”的字面值,发现有,则b存放的这个字面值指向的对象t的地址。
因此a==b返回true。
如果执行String c="cmd";执行过程会将c存放到栈中,然后去栈中检查是否存在"cmd"的字面值,发现没有,先在栈中生成一个字面值“cmd”,然后在堆中生成一个对象m,m的字符串值指向“cmd”的字面值地址。c存放指向m对象的堆内存地址。
如果是遇到String d = new String("abc");会将d存放到栈中,然后直接在堆中生产对象,对象的字符串值为abc,然后d存放的是执行该对象的地址。因此d==a返回false。
先说说栈的作用:
首先栈通常是与线程息息相关的,当一个线程运行时,就会给该线程分配一个对象的栈空间(多个线程会分配多个栈空间,因此如果方法中都是局部变量的话,多线程之间是互不干扰的,如果是含有操作成员变量的话,可能就需要考虑资源同步的问题了),当线程执行某个方法时,会将该方法的传入的参数存入栈中,当方法中创建基本类型的局部变量时,局部变量会放到栈中,当方法中创建对象时,会先去方法区查找响应的class信息,如果没有会去现加载class信息到方法区,对象的引用会放到栈中,类的实例对象会放到堆中。
栈的优点是访问速度快,缺点是栈中的数据大小和声明周期是固定的。
堆的优点是大小是动态分配的。生命周期也不是固定的。缺点就是访问速度慢。
同时栈还有一个特点就是同一个线程对应的栈的数据是共享的。
如:int a = 1;
int b = 1;
上面创建了2个局部变量,执行时会先创建一个a的引用,该引用是存放到栈中的。然后看栈中是否有1的字面值,如果没有就在栈中开辟个空间生成字面值1.a的引用存放的是指向字面值1的地址。接着执行创建引用b,同理b也是存在栈中的。然后检查栈中是否存在为1的字面值,发现存在,因此b引用存放的也是执行字面值1的地址。因此a==b返回true。
接着再说一个特例String
实例1
String a = "abc";
执行时先将引用a存放到栈中,然后检查栈中是否有字面值为"abc"。发现没有则创建一个“abc”的字面值,然后创建一个新的String对象t,然后这个t对象的字符串值存放的是指向“abc”字面值的地址。然后“abc”字面值再加上一个标识指向对象t。最后引用a存放的是执行t堆内存的地址。
如果此时再执行一个String b = "abc";则会先在栈中存放一个b引用,然后检查栈中是否有“abc”的字面值,发现有,则b存放的这个字面值指向的对象t的地址。
因此a==b返回true。
如果执行String c="cmd";执行过程会将c存放到栈中,然后去栈中检查是否存在"cmd"的字面值,发现没有,先在栈中生成一个字面值“cmd”,然后在堆中生成一个对象m,m的字符串值指向“cmd”的字面值地址。c存放指向m对象的堆内存地址。
如果是遇到String d = new String("abc");会将d存放到栈中,然后直接在堆中生产对象,对象的字符串值为abc,然后d存放的是执行该对象的地址。因此d==a返回false。