理解内存就理解一切。 这句话是听的马士兵老师的一句话,说的非常的对!

 一旦理解内存的分配不但对Java理解会比较深,到一个know how的阶段,而且对编程语言也会有一个本质的了解。而且随着学习的深入发现,很多核心问题也都是关于内存的。

所以想谈谈自己对内存的一些看法。

 1 , 内存结构图

java cli 内存 java内存详解_数组




1 ,Java内存分配中的栈 --stack


当在一段代码块定义一个基本类型的变量数据和对象的引用变量时,Java就在栈中 为这个变量分配内存空间,当该变量退出该作用域后,Java会自动释放掉为该变量所分配的内存     空间,该内存空间可以立即被另作他用。


例如:


 在函数中定义的一些基本类型的变量数据和对象的引用变量都在函数的栈内存中分配。


 当函数体结束的时候,函数出栈,函数体内定义的局部变量被释放掉。而且,成员变量和局部变量重名的时候,函数内部会访问局部变量。

2,Java内存分配中的堆--heap



堆内存用来存放由new创建的对象和数组。 在堆中分配的内存,由Java虚拟机的自动垃圾回收器来管理,当对象失去引用,其值为null,垃圾收集器自动回收掉。


在堆中产生了一个数组或对象后,还会在栈中定义一个特殊的变量,让栈中这个变量的取值等于数组或对象在堆内存中的首地址,栈中的这个变量就成了数组或对象的引用变量。  引用变量就相当于是 为数组或对象起的一个名称,以后就可以在程序中使用栈中的引用变量来访问堆中的数组或对象。引用变量就相当于是为数组或者对象起的一个名称。


引用变量是普通的变量,定义时在栈中分配,引用变量在程序运行到其作用域之外后被释放。而数组和对象本身在堆中分配,即使程序 运行到使用 new 产生数组或者对象的语句所在的代码块之外,数组和对象本身占据的内存不会被释放,数组和对象在没有引用变量指向它的时候,才变为垃圾,不能在被使用,但仍 然占据内存空间不放,在随后的一个不确定的时间被垃圾回收器收走(有一个线程每隔一段时间去扫描是否为null)。这也是 Java 比较占内存的原因。


思考一下,为什么要分栈和堆两种存储结构呢?


Thinking。。。。
答案来了,因为Java里函数是值传递和引用传递,传递实参的时候会把所传递的实参copy一下,发送过去一份副本,在函数内的操作是对副本的操作。这对于一些基本的数据变量还能接受,但是一个函数想访问另一个类里的内容。。。你总不能把整个类的副本发送过去吧,。。太占内存了。所以,现在只要发送一份指向所要访问类的对象的副本,就OK了。
     3,Java中的this。 
  this 的含义就是一个指向当前这个类在堆分配内存的首地址的指针, 等效于这个类的对象。也就可以访问这类的方法和属性。
eg :
假设有一个类叫Person 
 Person p = new Person();  
     p  和this是一样的在Person类里,即,p==this (实际代码不能这样写),不过这个person这个类的内部就可以直接调用this(除了被static修饰的代码块,比如在main方法里不能使用this),比较方便访问当前这个Person类的成员变量和方法,this.方法名  this.成员变量名(这样的话,如果Person继承了某些类的话,直接可以用this调用继承类的方法和字段)
     如果在另一个类Fruit中想去访问Person中的变量和方法 ,则必须产生对象才能调用。
   即:一个类的对象在这个类的内部可以表示为this,而在外部就是new出来的对象指针 ,Person p = new Person();  里的这个p
代码:

class A
 {
public int i =99;

public A(int i)
{
this.i = i; //在当前类的内部可以直接使用this,访问成员变量,为其赋值。
}


public void show()  
{
System.out.printf("i = %d\n", i); 
}
 }


 public class TestThis_1
 {
public static void main(String[] args)
{
A a = new A(10);//这里必须产生对象。

a.show();

}
 }



 4,Java中的static 。 
     被static 修饰的对象和方法被称为,类对象,类属性,直接可以用类名进行调用,不用产生对象就能直接调用。
     static变量类被载入时创建,只要类存在,static变量就在,所以不能声明在方法体内。
    根据上面的那个内存图,static变量存储在date segment里。


思考下面为什么?
静态变量不可以访问非静态
非静态可以访问静态。
static方法不能以任何方法引用this和super关键字。


因为静态方法使用前不用创建任何 实例对象,当静态方法被调用时,this,super的对象根本没有产生(还没被载入到运行时的堆中)。
这样就产生了矛盾。