【JVM】 java内存区域与内存溢出异常
前言
此系列博客是读《深入理解java虚拟机》所做的笔记整理。
No1. JVM内存管理这堵墙?
- 对C和C++的开发人员来说,在内存管理领域,他们既拥有每一个对象的“所有权”,也担负着每一个对象生命开始到终结的维护责任。
- 对java程序猿来说,在虚拟机自动内存管理机制的帮助下,不再需要为每一个new操作去写配对的delete/free代码,不容易出现内存泄露和内存溢出的问题。但是也出现问题:如果不理解虚拟机是怎么使用内存的,排查错误将会是一项非常艰难的工作。
No2.运行时数据区域
java虚拟机在执行java程序的时候,会把它所管理的的内存分成若干个不同的数据区。包括如下几部分:
- 程序计数器:
&概念与存储:一块较小的内存空间,看做是当前线程所执行的字节码的行号指示器。
&特性: 线程私有的内存。
因为java虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的,任意时刻,一个处理器都智慧执行一个线程中的指令,所以每个线程都需要有一个独立的程序计数器。
&异常:没有规定任何OutOfMemeoryError情况的区域。
- java虚拟机栈
& 概念与存储:描述java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧,用于存储局部变量表、操作数栈,动态链接,方法出口等信息。每个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。
其中,64位长度的long和double类型的数据会占用2个局部变量空间,其余的数据类型只占用1个。局部变量表所需的内存空间在编译期间完成分配,空间是完全确定的,在方法运行期不会改变局部变量表的大小。
&特性:线程私有,生命周期与线程相同。
&异常:
stackOverflowError:线程请求栈深度大于虚拟机所允许的深度。
OutOfMemeoryError:扩展时无法申请到足够内存。
- 本地方法栈
与虚拟机栈作用相似,区别就是虚拟机栈为虚拟机执行java方法服务,而本地方法栈则为虚拟机使用到的Native方法服务。Sun HotSpot将两者合并。
- java堆
&概念于存储:是java虚拟机所管理的内存中最大的一块。在虚拟机启动时创建。唯一目的就是存放对象实例。
&特性:线程共享的一块区域。
&其他:java堆是垃圾收集器管理的主要区域,也被称为GC堆。从内存回收的角度来看,现在收集器基本采用分代收集算法,所以:
&分类:新生代、老年代。或者(Eden空间,From Survivor空间,To Survivor空间等)。
- 方法区
&概念与存储:存储已经被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据。
java虚拟机规范把方法区描述为堆的一个逻辑部分,但她还有一个别名叫Non-Heap(非堆),目的是与java堆区分开。很多人愿意把方法区称为永久代。
&特性:线程共享
运行时常量池
&概念:是方法区的一部分。Class文件中除了有类的版本,字段,方法,接口等描述信息外,还有一项信息是常量池,用于存放编译期间生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存储。
&特点:动态性,java语言并不要求常量一定只有编译期才能产生,运行期间也能将新的常量放入池中。
另外,没有存储的规范。
小结:
运行时数据区域就先介绍到这里。接下来将介绍java堆中的实例。