`
smartwgd
  • 浏览: 53850 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

数据都存放在哪里?

    博客分类:
  • java
阅读更多


数据都存放在哪里?
1.寄存器。记得以前汇编里面有学习过,叫做register的东西,Java里面接触不到这个。
2.栈。Stack。放在RAM里面,随机存储器用来存储基础类型,例如short int long float double char byte boolean等,或者用来存储对象的引用。
例如:
A a = new A();
A b = a;
A c = a;
这里的b,c都是放在栈里面。
3.堆。Heap,也放在RAM里面,例子里面的a就是放在这里的。凡是new 出来的。。。不过String放在哪里的呢?是不是也放在这里呢?
String s = "abc";//这里"abc"存放在常量存储区,s是引用,所以s在栈里面。
String s2= new String("abc"); //s2是new出来的,所以在堆里面。
String s3 = "abc"+"def"; // 如果"abcdef"已经在常量存储器里面创建了,那么s3就是引用,放入Stack,否则s3就在堆里
4.静态存储区,也在RAM里面。也就是Static声明的字段都放在这里,那Static声明的方法和类是不是也放在这里呢?
5.常量存储区,在ROM,只读存储器。用来放final声明的。
6.非RAM中。例如数据库,例如网络流中,用那种持久化技术存起来就好了。

其实我们可以将上面的6个部分笼统的分为4个,寄存器,栈(包括栈,静态存储区,常量存储区),堆,非RAM。寄存器和非RAM不在我们讨论范围内。只关心栈和堆。
先来段程序。
主程序:
Test t = new Test();
t.see();

具体的类:
class Test{
static int s1=1;
String s2="abc";

public void see(){
int i=0;
System.out.println("see");
}
}
解释一下这段程序,先将主程序指令存入Stack,执行,第一句的时候,在Heap里面为t分配空间,建立对象实例的属性值,属性类型,以及对象本身的类型标记,在Stack里面建立对象的方法。最终将Heap里面t的4字节地址返给Stack中,等到t.see()调用的时候,see()方法默认传个隐藏参数进来,即调用see方法的对象的Heap地址,然后执行。
为什么静态方法不能调用非静态属性?
因为静态方法是最开始load进来的,放在Stack里,可以直接通过栈寻址找到它的,而非静态属性则是存放在Heap里面,只有实例化出具体对象才能存在。

 

 

下面转载一篇文章,出处找不到了。。

 从JVM内存管理的角度谈谈静态方法和静态属性

作者     robbin   (http://hibernate.fankai.com/站长)  
   
  我试着从JVM的内存管理原理的角度来谈一下静态方法和静态属性的问题,不对的地方请指正。  
  JVM的内存分为两部分:stack和heap:  
   
  stack(栈)是JVM的内存指令区。stack管理很简单,push一定长度字节的数据或者指令,stack指针压栈相应的字节位移;pop一定字节 长度数据或者指令,stack指针弹栈。stack的速度很快,管理很简单,并且每次操作的数据或者指令字节长度是已知的。所以Java基本数据类 型,Java指令代码,常量都保存在stack中。  
   
  heap(堆)是JVM的内存数据区。heap的管理很复杂,每次分配不定长的内存空间,专门用来保存对象的实例。在heap中分配一定的内存来保存对象 实例,实际上也只是保存对象实例的属性值,属性的类型和对象本身的类型标记等,并不保存对象的方法(方法是指令,保存在stack中),在heap中分配 一定的内存保存对象实例和对象的序列化比较类似。而对象实例在heap中分配好以后,需要在stack中保存一个4字节的heap内存地址,用来定位该对 象实例在heap中的位置,便于找到该对象实例。  
   
  由于stack的内存管理是顺序分配的,而且定长,不存在内存回收问题;而heap则是随机分配内存,不定长度,存在内存分配和回收的问题;因此在JVM 中另有一个GC进程,定期扫描heap,它根据stack中保存的4字节对象地址扫描heap,定位heap中这些对象,进行一些优化(例如合并空闲内存 块什么的),并且假设heap中没有扫描到的区域都是空闲的,统统refresh(实际上是把stack中丢失了对象地址的无用对象清除了),这就是垃圾 收集的过程。  
   
  我们首先要搞清楚的是什么是数据,什么是指令?然后要搞清楚对象的方法和对象的属性分别保存在哪里?  
   
  为了便于描述,我简单的统称:  
   
  1)方法本身是指令的操作码部分,保存在stack中;  
   
  2)方法内部变量作为指令的操作数部分,跟在指令的操作码之后,保存在stack中(实际上是简单类型保存在stack中,对象类型在stack中保存地址,在heap中保存值);  
   
  上述的指令操作码和指令操作数构成了完整的Java指令。  
   
  3)对象实例包括其属性值作为数据,保存在数据区heap中。  
   
  非静态的对象属性作为对象实例的一部分保存在heap中,而对象实例必须通过stack中保存的地址指针才能访问到。因此能否访问到对象实例以及它的非静态属性值完全取决于能否获得对象实例在stack中的地址指针。  
   
  先分析一下非静态方法和静态方法的区别:  
   
  非静态方法有一个和静态方法很重大的不同:非静态方法有一个隐含的传入参数,该参数是JVM给它的,和我们怎么写代码无关,这个隐含的参数就是对象实例在 stack中的地址指针。因此非静态方法(在stack中的指令代码)总是可以找到自己的专用数据(在heap中的对象属性值)。当然非静态方法也必须获 得该隐含参数,因此非静态方法在调用前,必须先new一个对象实例,获得stack中的地址指针,否则JVM将无法将隐含参数传给非静态方法。  
   
  而静态方法无此隐含参数,因此也不需要new对象,只要class文件被ClassLoader   load进入JVM的stack,该静态方法即可被调用。当然此时静态方法是存取不到heap中的对象属性的。  
   
  总结一下该过程:当一个class文件被ClassLoader   load进入JVM后,方法指令保存在stack中,此时heap区没有数据。然后程序技术器开始执行指令,如果是静态方法,直接依次执行指令代码,当然 此时指令代码是不能访问heap数据区的;如果是非静态方法,由于隐含参数没有值,会报错。因此在非静态方法执行前,要先new对象,在heap中分配数 据,并把stack中的地址指针交给非静态方法,这样程序技术器依次执行指令,而指令代码此时能够访问到heap数据区了。  
   
  再说一下静态属性和动态属性:  
   
  前面提到对象实例以及动态属性都是保存在heap中的,而heap必须通过stack中的地址指针才能够被指令(类的方法)访问到。因此可以推断出:静态 属性是保存在stack中的(基本类型保存在stack中,对象类型地址保存在stack,值保存在heap中),而不同于动态属性保存在heap中。正 因为都是在stack中,而stack中指令和数据都是定长的,因此很容易算出偏移量,也因此不管什么指令(类的方法),都可以访问到类的静态属性。也正 因为静态属性被保存在stack中,所以具有了全局属性。  
   
  总结一下:静态属性保存在stack指令内存区,动态属性保存在heap数据内存区。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics