Java的内存结构

Java中的内存结构

在说明他们在内存中如何存储之前,先要对内存中的存储区域进行讲解。

存储数据的地方有:

1、寄存器(程序计数器Program Counter Register)

在CPU内部,是最快的存储区。在字节码解释器工作时,就是通过改变程序计数器的值来选取下一条要执行的指令,分支、循环、跳转、等基础功能都是依赖此技术区完成的。在java多线程方面,多线程就是通过线程轮流切换而达到的,同一时刻,一个内核只能执行一个指令,所以,对于每一个程序来说,必须有一个计数器来记录程序的执行进度,这样,当线程恢复执行的时候,才能从正确的地方开始,所以,每个线程都必须有一个独立的程序计数器,这类计数器为线程私有的内存。如果一个线程正在执行一个Java方法,则计数器记录的是字节码的指令的地址,如果执行的一个Native方法,则计数器的记录为空,此内存区是唯一一个在Java规范中没有任何OutOfMemoryError情况的区域。

2、栈(Stacks)

位于RAM(通用随机访问存储器)中,分配存储的方法速度仅次于寄存器。创建程序时,系统必须知道存储在栈内所有项(iterm)的确切生命周期,以便上下移动指针,这一约定限制了程序的灵活性。存储的内容是基本类型的变量(形参、方法内定义的局部变量)和对象的引用变量(地址)以及方法调用。当超过当超过变量的作用域后,Java会自动释放掉该变量,内存空间可以立即被另作他用。
Java的内存结构_第1张图片
下面是上图的实例代码:

public void Bar(){
    int i;
}
public void Foo(int x){
    int i,m;
    Bar();
}

上面的代码中,先执行Foo()方法,所以将Foo()及其参数 (i,x,m)方法载入栈中,top指向Foo()方法,执行过程中,发现Foo()方法调用了Bar()方法,为Bar()方法分配一个栈块,将Bar方法及其参数 i 载入到栈块中,位于Foo()方法的上面,top指向Bar()方法,当执行完Bar()方法之后,自动收回其所在的栈块,进行出栈操作,top指向Foo()方法,然后继续执行Foo()方法,当其执行完以后,自动收回存放了该方法及其参数的存储空间,top指向栈底。

由上述的我们可以看出为什么用栈来存放局部变量的一些原因了,由此可见数据存储的内存结构是和程序的执行息息相关的。

3、堆(Heap)

也为与RAM中,用于存放对象实例(包含里面的实例变量,即实例变量即所属对象的成员变量)和数组。在使用堆存储时,能够动态的分配内存空间,而不需要知道存储的数据的生命周期。这种动态分配内存大小的代价是用堆进行存储分配和清理时比用栈更花费时间。由Java虚拟机的自动垃圾回收器来回收不再使用的数据。

4、其他内存区

Java虚拟机中还有与垃圾收集器相关的内存区域,如方法区(method area)、常量区(constant pool)以及本地栈(method stack)。

此外JVM中的堆还包括三种空间:
1. 持久代(permanent generation):保留JVM存放类和方法的反射对象。
2. 旧生代(old generation):用来存放tenured的对象。
3. 新生代(young generation):用来存放新建的对象和aged对象。新生代包括eden和两个survivor space。eden用来存放新创建的对象,survivor space用来存放还没有tenured的对象

你可能感兴趣的:(Java)