JAVA 数据结构存储剖析
实用举例:
1、堆浅(stack)
方法的参数值
public void sun(int a, int b)
//调用方法是在栈内存中为参数分配存储空同, 方法结束自动释放 。
局部空量
public static void main(String[] args){ int a=5; }
//在方法中的局部空量 , 存储在栈内存中, 方法结束时候, 释放内存
引用变量
Person p= new Person("zhaeyue", 22);
调用构造方法的时候,“形参”先在堆栈中开辟内存,存放“实參”, 再把“实参” 的一份拷贝传入对象之中。此时,“实参”的拷贝存放在堆(heap)中,构造方法结束,堆栈中的内存释放。
堆栈的存储要领:压栈,出栈,自动清除!
2、堆(heap)
成员变量:
public class Person{String name; int age;}
// New的时候存储在堆中。
new 得到的对象:
Person p= new Person("zhaoyue", 22);
New的时候存储在堆中 。
3、数据区(Data segment)
3.1、静态存储(static storage):
静态変量:
public static int a= 5;
//JVM 运行时首先为其开辟空间,位置不变,程序运行结束时空间释放 。 并且在运行时只加载一次。
静态方法
public static void run(){ prinlt("hello"); }
//JVM 运行时首先为其开辟空间,位置不变,程序运行结束时空间释放 。并且在运行时只加載一次。
3.2、地址池(address pool)
非new的字符串
String s="hello world";
3.3、方法区(method area)
成员方法:
public void run{System.out.println("I'm run!");}
//类装载的时候存在方法区,初始时被隐藏,实例化对象时被激活。
3.4、常量存储(constant storage)
常量:
public final int a= 5;
4、Code segment(代码区):存放代码
具体解释:
在java中有6种存取机制:
l、寄存器(register)
2、堆栈(stack)
3、堆(heap)
4、静态存储(static storage)
5、常量存储(constant storage)
6、非RAM存储
1、寄存器(register): 这是最快的存储区,因为它位于不同于其他存储区的地方——处理器内部。但是寄存器的数量极其有限,所以寄存器由编译器根据需求进行分配。你不能直接控制,也不能在程序中感觉到寄存器存在的任何迹象。
2、堆栈(stack)。位于通用RAM中,但通过它的“堆栈指针”可以从处理器哪里获得支持。堆栈指针若向下移动,则分配新的内存;若向上移动,则释放那些 内存。这是一种快速有效的分配存储方法,仅次于寄存器。创建程序时候,JAVA编译器必须知道存储在堆栈内所有数据的确切大小和生命周期,因为它必须生成 相应的代码,以便上下移动堆栈指针。这一约束限制了程序的灵活性,所以虽然某些JAVA数据存储在堆栈中——特别是对象引用,但是JAVA对象不存储其中。
3、堆(heap)。一种通用性的内存池(也存在于RAM中),用于存放所以的JAVA对象。堆不同于堆栈的好处是:编译器不需要知道要从堆里分配多少存储区 域,也不必知道存储的数据在堆里存活多长时间。因此,在堆里分配存储有很大的灵活性。当你需要创建一个对象的时候,只需要new写一行简单的代码,当执行 这行代码时,会自动在堆里进行存储分配。当然,为这种灵活性必须要付出相应的代码。用堆进行存储分配比用堆栈进行存储存储需要更多的时间。
4、静态存储(static storage)。这里的“静态”是指“在固定的位置”。静态存储里存放程序运行时一直存在的数据。你可用关键字static来标识一个对象的特定元素是静态的,但JAVA对象本身从来不会存放在静态存储空间里。
5、常量存储(constant storage)。常量值通常直接存放在程序代码内部,这样做是安全的,因为它们永远不会被改变。有时,在嵌入式系统中,常量本身会和其他部分分割离开,所以在这种情况下,可以选择将其放在ROM中。
6、非RAM存储。如果数据完全存活于程序之外,那么它可以不受程序的任何控制,在程序没有运行时也可以存在。
速度:
就速度来说,有如下关系:
寄存器<堆桟<堆<其他
关系:
然后我主要说下堆与堆栈的关系:
堆:堆是heap,是所谓的动态内存,其中的内存在不需要时可以回收,以分配给新的内存请求,其内存中的数据是无序的,即先分配的和随后分配的内存并没有什么必然的位置关系,释放时也可以没有先后顺序。一般由使用者自由分配,malloc分配的就是堆,需要手动释放。
堆栈:就是STACK。实际上是只有一个出入口的队列,即后进先出(First In Last Out),先分配的内存必定后释放。一般由,由系统自动分配,存放存放函数的参数值,局部变量等,自动清除。
还有,堆是全局的,堆栈是每个函数进入的时候分一小块,函数返回的时候就释放了,静态和全局变量,new 得到的变量,都放在堆中,局部变量放在堆栈中,所以函数返回,局部变量就全没了。
JAVA中的基本类型,其实需要特殊对待。因为,在JAVA中,通过new创建的对象存储在“堆”中,所以用new 创建一个小的、简单的变量,如基本类型等,往往不是很有效。因此,在JAVA中,对于这些类型,采用了与C、C++相同的方法。也就是说,不用new 来创建,而是创建一个并非是“引用”的“自动”变量。这个变量拥有它的“值”,并置于堆栈中,因此更高效。
再说一说类的实例方法!
类的实例方法在内存中是只有一份,不过肯定不会是第一个对象中,如果是第一个对象的话,那么当第一个对象被销毁的时候,那么后面的对象就永远无法调用了。
类的实例方法存在一个专门的区叫方法区(method area),事实上类刚装载的时候就被装载好了,不过它们在"睡眠",只是这些方法必须当有对象产生的时候才会"苏醒".(比如,一个输出类的成员变量的方法,如果连对象都没有,何来的输出成员变量).所以,方法在装载的时候就有了,但是不可用,因为它没有指象任何一个对象。
而静态的又不一样了,静态的东西存在静态存储(static storage)区,他们和类是一个等级的,就是说只要类被装载,它们就可以直接用.(用类名来调用).他们不依赖与任何对象,所以也不能输出任何对象的成员属性.(除非成员属性也是静态的)。
每个对象在new的时候都会在堆区中开辟内存,用来保存对象的属性和方法.(实际上方法保存的只是方法区的引用,如果保存的是方法本身,那么试想一下,有多少个对象就得有多少个方法,那么又和第一点中"实例方法在内存中只有一份拷贝"相矛盾了)。
如果您认真看完这篇文章,估计 java中内存方面肯定会有所帮助,这篇文章是我总结归纳出来的,并非完全自己写的。有什么不对的地方,欢迎批评指正。