JVM内存模型

这里写图片描述
前面的文章中讲到,JVM内存结构中每个区域都担当着不同的角色。弄清楚这些区域的功能和各自的生命周期对java语言的使用是很有必要的。

一 程序计数器

程序计数器(Program Counter Register),它是java虚拟机规范中唯一一个没有规定任何OutOfMemoryError情况的区域。每一个线程都有一个独立属于自己的程序计数器,它是线程私有的,所以它是随着线程的创建而创建。当线程执行一个java方法时,计数器记录的是当前正在执行的虚拟机字节码指令的地址,指向下一条要执行的指令地址;当执行的是一个本地方法(Native Method)时,这个计数器的值为空(Undefined)。

二 方法区

方法区(Method Area)是各个线程共享的内存区域,用于存储已经被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。通常将该区域与永久区关联在一起(这两者并不等价,这是针对HotSpot虚拟机的,其他的如BEA JRockit、IBM J9等虚拟机来说则没有永久区的概念)。方法区可以不需要连续的内存并且可以选择固定大小或者可扩展,还可以选择不实现垃圾收集。这个区域的内存回收的目标主要是针对常量池(JDK 1.7以后,存放String等常量信息的常量池已经从这里移除了)的回收和对类卸载。

三 java 堆

java 堆(java Heap)可以说是与程序的开发是最密切相关的。它是java虚拟机所管理的内存中最大的一块。是被所有线程共享的一块区域,在虚拟机启动时创建。该区域的唯一目的就是存放对象实例,几乎所有的对象实例和数组都在这里分配内存。当然这并不是绝对。java堆是垃圾回收器管理的主要区域。因为现在的内存管理基本上都是采用的分代收集算法,因此java堆可以细分为:新生代和老年代。
新生代还分为Eden区、From区和To区。Eden是伊甸园的意思,是所有对象实例产生的地方。From区和To区是两块大小相同的区域,使用的垃圾回收机制是复制算法。具体关于垃圾回收机制的内容会在后面的文章中整理。
java堆是可以处在不连续的内存空间中,只要保证逻辑上是连续的。可以固定大小也可以是可扩展的(通过-Xms 和 -Xmx 参数控制)。

四 java 栈

与PC寄存器一样,java栈(java Vritual Machine Stacks)也是线程私有的,由一系列的帧组成,所以又称帧栈。java栈描述的是java方法执行的内存模型:每个方法在执行时都会创建一个栈帧用于存放局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行完成的过程,就对应着一个栈帧在栈中入栈到出栈的过程。可以看出,java栈并不需要垃圾回收,因为当一个方法执行完成后,栈中的数据已自动清空。

1 局部变量表

局部变量表 存储的不仅仅是局部变量,而是包括参数和局部变量。
这里写图片描述
如上图,当执行第一个静态方法时,对应的右面的第一个栈帧入栈,并且每一列中保存着对应的参数与局部变量。而下面的实例方法则有些不同,这里的第一列中存储的是执行当前方法的实例引用。

2 操作数栈

java中的所有参数传递使用的都是操作数栈。我们以一个简单的加法程序为例:
这里写图片描述
以a=100, b=98为例。右下角是反编译后代码的一部分。
0: iconst_0 // 压栈 a、b、c压入局部变量表中(图中开始之前应该c = 0没有画出来)
1: istore_2 // 弹出int,存放于局部变量2
2: iload_0 // 把局部变量0压栈,即把a压入操作数栈中
3: iload_1 // 局部变量1压栈,即把b压入操作数栈中
4: iadd //弹出2个变量,求和,将结果压入操作数栈中
5: istore_2 //弹出结果,放于局部变量2
6: iload_2 //局部变量2压入局部变量中
7: ireturn //返回

五 堆、栈、方法区交互

这里写图片描述

public   class  AppMain     
 //运行时, jvm 把appmain的信息都放入方法区 
{  
  public   static   void  main(String[] args) {  
  Sample test1 = new  Sample( " 测试1 " );  
 //test1是引用,所以放到栈区里, Sample是自定义对象应该放到堆里面 
 Sample test2 = new  Sample( " 测试2 " );  
 test1.printName();  
 test2.printName();  
 } 
 
public   class  Sample       
 //运行时, jvm 把Sample的信息都放入方法区  
 { 
  private  name;     
 //new Sample实例后, name 引用放入栈区里,  name 对象放入堆里 
  public  Sample(String name) {  
  this .name = name; }  
  //print方法本身放入方法区里。 
  public   void  printName()     
  {  
  System.out.println(name);  
  } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值