浅谈JVM内存结构

内存是操做系统中不可或缺的部分,一台机器有内存才能正常稳定地运行。编程语言从来都有本身的内存管理机制,尤为是Java,它不像C同样须要本身维护内存的关系,而是经过本身的内部机制JVM来管理内存。这虽然下降了开发同窗们的入手难度,但同时也使得在运行时一旦抛出内存异常,很难知道发生了什么。如下就简单地来介绍一下JVM内存的结构。编程

废话很少说,先看下面图表:数据结构

▲图表1 JVM总体结构▲多线程

此时可能有些人会一头雾水,别着急,咱们一点点来看。编程语言

先看第一部分:学习

▲图表2 类装载系统▲优化

这个表明了一个类被装入JVM的过程。若是用更简单的比喻,它相似初学JDBC时Class.forName()所作的事情。具体来说,会分为如下几步:spa

  1. 加载:将字节码文件按照双亲委托机制(当某个类加载器须要加载某个.class文件时,它首先把这个任务委托给他的上级类加载器,递归这个操做。若是上级的类加载器没有加载,本身才会去加载这个类,方块中对应的即是Bootstrap Class Loader(启动类加载器),Extension Class Loader (标准扩展类加载器),Application Class Loader(系统类加载器))进行加载;
  2. 连接字节码文件:分为三个步骤,分别是字节码验证(verify)、class类数据结构分析(prepare)以及相应的内存分配和最后的符号表的连接(resolve);
  3. 初始化操做:好比类中静态属性和初始化赋值,以及静态块的执行等。

一个类就是这样被装入了内存,那么在程序中会发生什么呢?别着急,且听我慢慢道来:操作系统

▲图表3 Java内存结构▲线程

这张图是运行时数据区,表示了当前JVM的全部状态,让咱们一个区一个区看看:3d

1. 方法区(Method Area):用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码。运行时常量池也是方法区的一部分,好比String w = ”hello”;中,hello就被放在了方法区里。方法区是线程共享的。有一点要注意,JDK1.8 使用元空间 MetaSpace 替代方法区,元空间并不在 JVM中,而是使用本地内存;

_2. 堆区(Heap Area):_堆区是JVM中占地最大的区域,全部的实例对象所有都在堆区上,这个位置也是线程共享的;

3. 栈区(Stack Area):存放了每个线程的当前状态,每个线程都有一个本身的栈,而栈中存放了如下数据组成的一个个栈帧:操做数、局部变量表、动态连接、返回地址,须要注意的是,栈中只存引用或者基本类型,并且线程不共享(并无指内部的优化动做);

4. 程序计数器(PC Registers): 它是当前线程执行字节码的行号指示器。在多线程中,为了让每一个线程切换回来后可以恢复原来执行的指令,就须要为每一个线程启动一个PC计数器,这些计数器之间是互补影响的,由于程序计数器和栈同样都是线程私有的。固然程序计数器是JVM惟一个不会出现内存溢出的组件;

5. 本地方法栈(Native Method Statck):保存了本地方法,它是当程序调用类库(本地方法)中的方法时才会用到它,即native method。

接下来就要介绍为咱们勤勤恳恳工做的执行引擎啦:

▲图表4 Java执行引擎▲

Java执行分为编译执行(JIT compilation)解释执行(Interpreter)

首先咱们要明白什么是编译执行,什么是解释执行:

Bash就是属于解释执行语言,一行行解释代码来完成命令;

C就是编译执行, 将文件编译成字节码,接着运行。

那为何Java会用两套编译手段呢?先看下面这个例子:

假定你是导演,写了个剧本,让演员表演。

一种方式是让演员把整个剧本都背下来,吃透到脑子里,而后连续表演一个小时。

另外一种方式是让演员表演两分钟,再看两分钟脚本,思考一下,再表演两分钟,再看一会脚本,思考一下…

单纯从效率上来说,第一种方式必定会比第二种方式表演起来更熟练,可是现实每每不容许,或者没必要要。若是不是很是须要表演的技巧,简单地看一下剧本就好啦。在特别考验表演技巧时,才须要背下整个剧本,这样才能在表演时更好地展示本身的风采。

Java也是如此,由JIT发现热代码后,将指令集优化(好比重排,合并),而后生成字节码供系统运行。至于其余的代码呢,简单的解释执行完就行了~

在运行的过程当中必定会产生不少的垃圾,由于随着系统运行,不少对象都会废弃不用,此时就须要使用垃圾回收机制Garbage Collection(垃圾回收内容太多了,之后能够单拿出来说讲)。

最后,来看下Java与系统底层交互:

▲图表5 Java与系统底层交互▲

JNI(Java本地接口)经过使用Java本地接口书写程序,能够确保代码在不一样的平台上方便移植。经过JNI实现与本地方法库的调用交互,使得在Java虚拟机内运行的Java代码可以与其它编程语言互相操做,包括_建立本地方法、更新Java对象、调用Java方法,_引用Java类,捕捉和抛出异常等,也容许Java代码调用 C/C++或汇编语言编写的库。

好啦,今天就到这里,相信你们对JVM的内存模型已经有了必定的认知,但愿在遇到这种问题时,本篇内容能够帮到正在阅读的你。学习技术是一个日积月累的过程,切不可急躁~若是写代码有天意,那必定是让你修炼!

相关文章
相关标签/搜索