标签:des style blog color java 使用 os io
VM运行时数据区域:
根据《Java虚拟机规范(第二版)》的规定,JVM包括下列几个运行时区域:
我们思考几个问题:
1.jVM是怎么运行的?
2.JVM运行时内存是怎么分配的?
3.我们写的java代码(类,对象,方法,常量,变量等等)最终存放在哪个区?
VM运行时数据区域:
1.程序计数器(program Counter Register):
是一块较小的内存空间,它的作用可以看做是当前线程所执行的字节码的行号指示器。在虚拟机的概念模型里(仅是概念模型,各种虚拟机可能会通过一些更高效的 方式去实 现),字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个 计数器来完成。
由于Java虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的,在任何一个确定的时刻,一个处理器(对于多核处理器来说是一个内核) 只会执行一条线程中的指令。因此,为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各条线程之间的计数器互不影响,独立存 储,我们称这类内存区域为“线程私有”的内存。
如果线程正在执行的是一个Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是Natvie方法,这个计数器值则为空 (Undefined)。此内存区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。
2.java虚拟机栈(Java Virtual Machine Stacks):
里面存放的是本地变量表(存放了编译期可知的各种标量类型:Boolean,byte,char,short,int,float,long,double)、对象的引用(不是对象本身,仅仅是引用指针)、方法返回地址等。
虚拟栈中规定了两种异常状况:
- 如果线程请求的深度大于虚拟机所允许的深度,就会抛出stackoverflowerror异常,也就是栈溢出异常。在使用递归的调用方法的情况下,很容易抛出这个异常。
- 如果VM栈可以动态扩展,当扩展的时候无法申请到足够的内存空间,则抛出OutOfMemoryError异常,内存溢出。
3.本地方法栈(native method stacks)
这块区域在jvm运行内存中职责就相对比较少了。只是执行Native 方法。如果这个区的内存不足也是会抛出StackOverflowError 和 OutOfMemoryError 异常。
4.java 堆
这块区域是jvm中最大的一块区域了,java堆是被所有线程所共享的,也是GC主要的回收区,在jvm启动的时候就创建了。java堆的唯一的目的就是存放对象实例(所有new出来的对象)绝大部分对象的实例都是在这块区域分配。
从图中可以看出heap中还可以分为新生代(Young Generation)和老年代(Old Generation)。下面看这个图:
5.方法区(Mehod Area)
方法区和堆一样也是线程共享的区域,它主要是用于存储被虚拟机加载的类信息、常量、静态变量、及时编译器编译后的代码等数据,不属于heap的一部分。 相对来说,GC行为在这个区域是相对比较少发生的,但并不是某些描述那样永久代不会发生GC。对于sun公司的HotSpot虚拟机来说。gc也会对这块 区域进行垃圾回收,这里的回收主要是常量池的回收和对类的卸载。
如果细分方法区的里面有为运行时常量池(Runtime Constant Pool),它主要存储Class文件中的版本、字段、方法、接口等描述信息。还 有一项信息是常量表(constant_pool table)用于存放编译期已可知的常量,这部分内容将在类加载后进入方法区(永久代)存放。但是java语言并不要求常量一定只有编译期预先置入 Class的常量表的内容才能进入方法区常量池,运行期间才可以将新内容放入常量池(最典型的是String.intern()方法)
实战OutOfMemoryError:
除了程序计数器,其他在VMSpec中都描述了产生OutOfMemoryError(下称OOM)的情形,那我们就实战模拟一下,通过几段简单的代码,令对应的区域产生OOM异常以便加深认识,同时初步介绍一些与内存相关的虚拟机参数。
1.Java堆:
java 堆存放的是对象实例,因此只要不断建立对象,并且保证GCRoots到对象之间有可达路径即可产生OOM异常。测试中限制Java堆大小为20M,不可扩 展,通过参数-XX:+HeapDumpOnOutOfMemoryError让虚拟机在出现OOM异常的时候Dump出内存映像以便分析。
代码:
package com.lp.ecjtu;
import java.util.ArrayList;
public class JVMTestDemo_heap {
public static void main(String[]args){
java.util.List<OOMObject>list = new ArrayList<OOMObject>();
while(true){
list.add(new OOMObject());
}
}
}
/**
* VMArgs:-Xms20m-Xmx20m-XX:+HeapDumpOnOutOfMemoryError
* @author Administrator
*
*/
class OOMObject{
}
运行结果:
java.lang.OutOfMemoryError:Javaheapspace
Dumpingheaptojava_pid3404.hprof...
Heapdumpfilecreated[22045981bytesin0.663secs]
垃圾收集GC(GarbageCollection,下文简称GC):
GC的历史远远比java来的久,在1960年诞生于MIT的Lisp(是一门真正的使用内存冬天分配和垃圾回收集)的语言。当Lisp在胚胎时期,人们在GC需要做的3件事情:
总 结下:其中程序计数器、VM栈、本地方法栈随线程而生,随线程而灭;栈中的帧随着方法的进入退出,有条不紊的进行的出栈和入栈操作;每一个帧中分配多少内 存,基本上是在Class文件生成时就已知的(可能会由JIT动态晚期编译进行一些优化,但大体上可以认为是编译期可知
的),因此这几个区域的内存的分配和回收具备很高的确定性,因此在这几个区域不需要过多考虑回收问题。而java堆和方法区(包括运行时常量池)则不一样,我们必须等到程序实际运行期间才能知道会创建那些对象,这部分内存的回收和分配是动态的。
java学习-----jvm的内存分配及运行机制,布布扣,bubuko.com
标签:des style blog color java 使用 os io
原文地址:http://www.cnblogs.com/200911/p/3922704.html