黑马程序员技术交流社区

标题: java 栈内存,堆内存,方法区,常量池,静态区到底有什么关联 [打印本页]

作者: 大漠孤烟    时间: 2014-4-21 00:24
标题: java 栈内存,堆内存,方法区,常量池,静态区到底有什么关联
java 栈内存,堆内存,方法区,常量池,静态区到底有什么关联, 方法区,常量池,静态区又存在哪里啊,这些内存空间概念经常容易搞混淆。能给举例来区分吗?
作者: tjsyj    时间: 2014-4-21 00:28
栈:自动分配连续的空间,后进先出,一般用来放置局部变量,数据使用完毕之后,会自动释放  堆:不连续,用来放置 new出来的对象,堆中的数据都会有默认初始化值。引用类型的数据都是null,基本数据类型 int 是 0  string 是null boolean 是false  (默认初始化)   
方法区:属于堆的一部分,存放类的信息(代码)、static变量、常量池(字符串常量)等

作者: 々白点潜心ザ    时间: 2014-4-21 08:46
堆:堆主要存放Java在运行过程中new出来的对象,凡是通过new生成的对象都存放在堆中,对于堆中的对象生命周期的管理由Java虚拟机的垃圾回收机制GC进行回收和统一管理。

栈:栈主要存放在运行期间用到的一些局部变量(基本数据类型的变量)或者是指向其他对象的一些引用,当一段代码或者一个方法调用完毕后,栈中为这段代码所提供的基本数据类型或者对象的引用立即被释放;另外需注意的是栈中存放变量的值是可以共享的,优先在栈中寻找是否有相同变量的值,如果有直接指向这个值,如果没有则另外分配。

常量池:常量池在编译期间就将一部分数据存放于该区域,包含基本数据类型如int、long等和对象类型String、数组等并以final声明的常量值。特别注意的是对于运行期位于栈中的String常量的值可以通过 String.intern()方法将该值置入到常量池中。

静态域:存放类中以static声明的静态成员变量

方法区:主要存放一些代码段以供类调用的时候所共用。

作者: skill20    时间: 2014-4-21 12:51
栈:存放局部变量,调用的方法。
堆: 存放引用类型的对象,即new出来的对象。
方法区:存放静态变量,方法,常量池(String类型)。
作者: 大漠孤烟    时间: 2014-4-21 22:03
多谢各位了。。。
作者: 少先队员    时间: 2014-4-22 00:00
栈内存的东西 一般都是要进行 引用。
    一般都是建立对象然后对它进行引用。
作者: ﹊佑雨时杰↘    时间: 2014-4-22 00:41
Java中的内存分配区域主要由:堆、栈、常量池、静态域、代码区
堆(Heap):堆主要存放Java在运行过程中new出来的对象,凡是通过new生成的对象都存放在堆中,对于堆中的对象生命周期的管理由Java虚拟机的垃圾回收机制GC进行回收和统一管理。
栈(Stack):栈主要存放在运行期间用到的一些局部变量(基本数据类型的变量)或者是指向其他对象的一些引用,当一段代码或者一个方法调用完毕后,栈中为这段代码所提供的基本数据类型或者对象的引用立即被释放;另外需注意的是栈中存放变量的值是可以共享的,优先在栈中寻找是否有相同变量的值,如果有直接指向这个值,如果没有则另外分配。
常量池(ConstantPool):常量池在编译期间就将一部分数据存放于该区域,包含基本数据类型如int、long等和对象类型String、数组等并以final声明的常量值。特别注意的是对于运行期位于栈中的String常量的值可以通过 String.intern()方法将该值置入到常量池中。
静态域(StaticSegment):存放类中以static声明的静态成员变量
代码区(CodeSegment):主要存放一些代码段以供类调用的时候所共用。
举例:
public static void main(String[] args) {
  String a = "a";
  String tempa="a";
  String b = "b";
  String c = "c";
  String abc = "abc";
  String a_b_c = "a"+"b"+"c";
  String a_b = a+b;
  String ab = "ab";
  String newabc = new String("abc");
  String abcintern = newabc.intern();

  final String finalb = "b";
  String a_b2 = "a"+finalb;
  System.out.println(tempa==a);//true,在栈中共享同一个值,也可以理解为他们共同指向字符串常量池中的a
  System.out.println(newabc==abc);//false,newabc是指向堆的一个引用,abc是在位于栈中的String对象的一个引用变量,然后去字符串常量池中找abc字符串,如果找到则将该应用指向abc,如果找不到则将abc放入字符串常量池然后指向它。
  System.out.println(a_b==ab);//false,a_b是在运行期字符串的引用,而ab则是在编译期间就指定了
  System.out.println(a_b_c==abc);//true,a_b_c在编译期间就将常量字符串连接到一起,所以他们指向同一个字符串常量,而且"a"+"b"+"c",首先a和b组装成一个常量ab放于常量池中,然后ab和c组装在一起放于常量池中,然后将abc的地址赋给了a_b_c,由于String是不可变的,所以产生了很多临时变量。
  System.out.println(abcintern==abc);//true,调用intern()方法则将abc字符串放入了字符串常量池,返回值则是直接指向常量池中的字符串常量值所以相等
                     System.out.println(ab==a_b2);//true,finalb是因为声明为final修饰符它在编译时被解析为常量值的一个本地拷贝存储到自己的常量池中,相当于"a"+"b"
}
在面试中我们经常被问到String和StringBuffer的区别,如果从内存上理解了他们的存储那么就不难理解了:以下是JDK中对String的类的说明:
public final class Stringextends Objectimplements Serializable, Comparable<String>, CharSequence
String类代表字符串。Java 程序中的所有字符串字面值(如"abc")都作为此类的实例实现。
字符串是常量;它们的值在创建之后不能更改。字符串缓冲区支持可变的字符串。因为 String 对象是不可变的,所以可以共享。
因为String字符串是常量,所以他一旦初始化后值是不能变的,而且是可以共享的,存放于字符串常量池,需要在程序中做大量的字符串连接时采用StringBuffer来连接,如果直接采用String来连接由于他们的值是不能改变的,相当于还是采用了StringBuffer来连接了字符串,但是在连接过程中如果事先没声明Stringbuffer对象则中间工程中就会产生很多临时变量:
String str = null;
for(int i=0;i<100;i++){
str +=i;//每循环一次相当于产生了StringBuffer对象
作者: Mr.飞碍特    时间: 2014-4-22 09:26
1. 栈(stack)与堆(heap)都是Java用来在Ram中存放数据的地方。与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆。
2. 栈的优势是,存取速度比堆要快,仅次于直接位于CPU中的寄存器。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。另外,栈数据可以共 享,详见第3点。堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是,由于要 在运行时动态分配内存,存取速度较慢。
3. Java中的数据类型有两种。
一种是基本类型(primitive types), 共有8种,即int, short, long, byte, float, double, boolean, char(注意,并没有string的基本类型)。这种类型的定义是通过诸如int a = 3; long b = 255L;的形式来定义的,称为自动变量。值得注意的是,自动变量存的是字面值,不是类的实例,即不是类的引用,这里并没有类的存在。如int a = 3; 这里的a是一个指向int类型的引用,指向3这个字面值。这些字面值的数据,由于大小可知,生存期可知(这些字面值固定定义在某个程序块里面,程序块退出 后,字段值就消失了),出于追求速度的原因,就存在于栈中。
另外,栈有一个很重要的特殊性,就是存在栈中的数据可以共享。假设我们同时定义
  int a = 3;
  int b = 3;
编 译器先处理int a = 3;首先它会在栈中创建一个变量为a的引用,然后查找有没有字面值为3的地址,没找到,就开辟一个存放3这个字面值的地址,然后将a指向3的地址。接着处 理int b = 3;在创建完b的引用变量后,由于在栈中已经有3这个字面值,便将b直接指向3的地址。这样,就出现了a与b同时均指向3的情况。
特 别注意的是,这种字面值的引用与类对象的引用不同。假定两个类对象的引用同时指向一个对象,如果一个对象引用变量修改了这个对象的内部状态,那么另一个对 象引用变量也即刻反映出这个变化。相反,通过字面值的引用来修改其值,不会导致另一个指向此字面值的引用的值也跟着改变的情况。如上例,我们定义完a与 b的值后,再令a=4;那么,b不会等于4,还是等于3。在编译器内部,遇到a=4;时,它就会重新搜索栈中是否有4的字面值,如果没有,重新开辟地址存 放4的值;如果已经有了,则直接将a指向这个地址。因此a值的改变不会影响到b的值。
另一种是包装类数据,如Integer, String, Double等将相应的基本数据类型包装起来的类。这些类数据全部存在于堆中,Java用new()语句来显示地告诉编译器,在运行时才根据需要动态创建,因此比较灵活,但缺点是要占用更多的时间。
作者: 136616244    时间: 2014-4-25 23:07
我算了,不回复了,回复你也不一定看得到
作者: wawa    时间: 2014-4-26 00:14
恩,总结的很详细,同样也学习了:time:




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2