读书笔记之java内存区域

2/22/2017来源:ASP.NET技巧人气:1268

java虚拟机在执行Java程序的过程中会把它所管理的内存划分为以下若干个不同的数据区域,本文就是简单说明下这些区域的作用,服务对象以及其中可能产生的问题 1、程序计数器当前线程所执行的字节码的行号指示器,字节码解释器通过改变这个计数器的值来选取下一条需要执行的字节码指令。Java虚拟机是通过线程轮流切换并分配处理器的执行时间来实现多线程的,对于某个确定的时刻来说,一个处理器都只会执行一个线程中的指令,所以对于线程切换来说(为了保护线程的执行现场),每个线程都有自己独立的程序计数器,且各个线程的程序计数器互不影响,独立存储,又把这类内存区域称为“线程私有”的内存。如果线程正在执行的是一个Java方法,程序计数器记录的是正在执行的虚拟机字节码指令的地址,若执行的是Native方法(String.intern()就是Native方法,何为Native方法,这篇文章有详细说明点击打开链接),程序计数器的值则为空。程序计数器所占的内存区域是java虚拟机规范中没有规定任何有OutOfMemoryError的区域。      2、Java虚拟机栈:Java虚拟机栈也是线程私有的,生命周期同线程相同。虚拟机栈描述的的Java方法执行的内存模型:每个方法执行时会创建一个栈帧(stack Frame),用户存储局部变量表,操作数栈,动态链接,方法出口等信息。每一个方法从调用直到执行完毕的过程,对应着一个栈帧在虚拟机栈中入栈到出栈的过程。如果线程请求的栈深度超过虚拟机所允许的深度,就会抛出StackOverFlowError异常;如果虚拟机栈可以动态扩展(当前大部分Java虚拟机都可动态扩展),如果扩展时无法申请得到足够的内存,就会抛出OutOfMemoryError异常。   3、本地方法栈:同Java虚拟机栈发挥的作用非常相似,区别则是Java虚拟机栈为虚拟机执行Java方法(字节码)服务,而本地方法栈则为虚拟机使用的Native方法服务。同Java虚拟机栈一样,本地方法栈也会抛出StackOverFlowError和OutOfMemoryError 异常。  4、Java堆(Heap):对大多数应用来说,Java Heap是Java虚拟机所管理的内存中最大的一块,Java Heap是被所有线程共享的一块内存区域,虚拟机启动时创建,此内存区域的唯一目的就是存放实例对象,几乎所有的实例对象和数组都要在堆上分配。(原书是介绍说随着JIT编译器发展和逃逸分析技术的逐渐成熟,栈上分配,标量替换优化技术将会导致一些微妙的变化,所有的对象都分配在堆上变得不是那么绝对)(这个不了解)。 Java Heap是垃圾回收器管理的主要区域,所有又被称为GC堆(Garbage collected Heap),Java Heap可以处在物理上不连续的内存空间,但是逻辑上得是连续的。如果在堆中没有内存完成实例分配,并且堆也无法扩展时,就会抛出OutOfMemoryError异常。  5、方法区(Method Area):同Java Heap也是各个线程共享的内存区域,用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据,虽然Java虚拟机规范吧方法区描述为堆的一个逻辑部分,但它的别名Non-Heap(非堆),可见一斑,目的就是为了与Java Heap区分开。(又称“永久代”,本质上两者并不等价,仅仅是因为HotSpot虚拟机的设计团队使用永久代替代了方法区)。当方法区无法满足内存分配需求时,就会抛出OutOfMemoryError异常。 6、运行时常量池(Runtime Constant Pool):也是方法区的一部分,class文件中出了有关类的字段,方法等描述信息外,还有一项是常量池(Constant Pool Table),常量池用与存放编译器生成各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。不过运行时常量池相对于Class文件常量池,有另一个重要特征就是具备动态性,Java语言并不要求常量一定只有编译期才能产生(意思是:并非预置入Class文件中常量池的内容才能进入运行时常量池),运行期间也能将新的常量放入池中,这个特性最广泛的应用就是String类的intern()方法。 7、直接内存(Direct Memory):Direct Memory并不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域,所以不受Java堆大小的限制,但是会受限于本机总内存的限制,所以也会导致OutOfMemoryError异常出现,最典型的应用就是java1.4中新加入的NIO(new Input/Output)类。