学过java知识和技术人,都应该听说过jvm,jvm一直是java知识里面晋级阶段的重要部分,如果想要在java技术领域更深入一步,jvm是必须需要明白的知识点。

本篇来讲解jvm的基础原理,先来熟悉一下大致的流程:

JVM运行流程:

  我们都知道java一直宣传的口号:一次编译,到处运行。也是它的跨平台性。这点的具体实现如下:

  java程序在经过一次编译之后,会将java代码编译成java字节码,也就是class文件。然后在不同的机器中依靠不同的java虚拟机来解析。
最后再转换为不同平台的机器码,最终得到执行。
  这样,我们就可以大胆的推测说,如果我们要在mac系统中执行,是不是就只需要安装一个mac的java虚拟机就可以执行java程序了。

了解了这个基本原理后,那一个普通的java程序它的执行流程到底是怎样的?例如以下的代码。

package helloWorld;
public class HelloWorld {
public static void main(String[] args) {
System.out.print("hello world");
}
}

  这段程序从编译到运行,最终打印出“Hello world”中间经过了哪些步骤,如下图;

java代码通过编译之后生成字节码文件(class文件),通过 java hello world执行,此时java会根据系统的版本找到jvm.cfg,它会根据系统版本放在不同的位置,我的在E:\SVN_ROOT\UMP_PROJECT\UMP1.0.0.0\14tools\jdk1.6.0_02\jre\lib\i386
打开可以看到:

其中-server KNOWN就表示名称为server的jvm可用,此时在电脑中搜索下jvm.dll文件,会发现是在某个server目录下。
E:\SVN_ROOT\UMP_PROJECT\UMP1.0.0.0\14tools\jdk1.6.0_02\jre\bin\server
简而言之就是通过jvm.cfg文件来找到对应的jvm.dll。这个jvm.dll文件就是java虚拟机的主要实现。
接下来会初始化jvm,并且获取JNI接口。
什么是JNI接口,就是java的本地接口(java不太好实现的与硬件或者操作系统相关的方法,一般是其他语言编写的。)。
也就是说java被编译成了class文件,jvm要通过这个JNI接口从硬盘上找到这个文件并装载到jvm里面。然后找到main方法执行。

JVM 基础结构:

  在上面的例子上,我们已经知道了java程序大致的流程,但是jvm是怎么去执行class文件的,看看以下图:

从这个结构不难看出,class文件被jvm装载以后,经过jvm的内存空间调配,最后由执行引擎完成class文件的执行。这个过程还需要其他角色模块的配合才能完成。。

jvm的内存空间
  jvm的内存空间包括:方法区,java堆,java栈,本地方法栈。

方法区是各个线程共享的区域,存放类信息,常亮,静态变量。

java堆也是线程共享的区域,存放类的实例,如果一个系统创建了很多类实例,如果java堆空间不足,程序就会抛出OutOfMemoryError异常。因此java堆空间是最大的。

堆被所有的线程共享,在虚拟机启动时,我们指定的"Xmx"之类的参数就是用来指定最大堆空间的指标。

理所当然,堆也是垃圾收集器重点照顾的区域,所以堆内空间还会被不同的垃圾收集器进行进一步的细分,最有名的就是新生代、老生代的划分。

java栈是每个线程私有的区域,它的生命周期与线程相同,一个线程对应一个java栈,每执行一个方法就会往栈中压入一个元素,这个元素叫“栈帧”。

而这个栈帧中包括了方法中的局部变量,用于存放中间状态值的操作栈。如果java栈空间不足了,程序会抛出StackOverflowError异常。

本地方法栈和java栈类似,只是它用来表示执行本地方法的,本地方法栈存放的方法是调用本地方法接口,最终调用本地方法库,实现与操作系统,硬件交互的目的。

PC寄存器,其实就是控制这些类对象,方法,静态变量,他们的执行顺序。它可以看做是当前线程说执行的字节码的行号指示器。由于jvm是多线程是通过轮流浅黄并分配处理器执行时间的来方式来实现的,在任何一个确定的时刻,一个处理器(对应多核处理器来说是一个内核)都只会执行一条线程中的指令。因此为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器(PC寄存器),各条线程之间计数器互不影响,独立存储,我们称这类内存区域为“线程私有的内存”。

执行引擎就是根据PC寄存器调配的指令顺序,一次执行程序指令。

对于程序中出现OutOfMemoyError,简单的总结如下:

  1、堆内存不足是最常见的OOM原因之一,抛出的错误信息是“java.lang.OutOfMemoryError:Java heap space”,原因可能千奇百怪。

   比如:可能存在内存泄露问题;也很有可能就是堆得大小不合理,比如我们要处理可观的数据量,但是没有显式指定JVM堆大小或者指定数据偏小;或者出现JVM处理引用不及时,导致堆积起来,内存无法释放等。

  2、Java虚拟机栈和本地方法栈,如果我们写一段程序不断的进行地柜调用,而且没有退出条件,就会导致不断的进行压栈。类似这种情况,JVM实际会抛出StackOverFlowError;当然,如果JVM试图去扩展栈空间的时候失败,就会抛出OutOfMemoyError。

  3、对于老版本的Oracle JDK,因为永久代的大小是有限的,并且JVM对永久代垃圾回收非常的不积极,所以当我们不断添加新类型的时候,永久代出现OutOfMemoyError也非常的多见,尤其是在运行时,存在大量动态类型生成的场合;类似Intern字符串缓存占用太多空间,也会导致OOM问题。对应的异常信息,会标记出来和永久代相关:“java.lang.OutOfMemoyError:PermGen space”。

  4、随着元数据区的引入,方法区内存以及不再那么窘迫,所以相应的OOM有所改观,出现OOM,异常信息则变成了:"java.lang.OutOfMemoyError: Metaspace"。

结语:

本文主要介绍了java虚拟机运行的基本流程,以及java虚拟机内部结构。下一篇我们将学习java内存模型以及探索java变量的可见性、有序性、指令重排等问题以及总结了可能会发现OutOfMemoyError异常的原因和所在。

JVM知识(一):基础原理的更多相关文章

  1. C#基础原理拾遗——引用类型的值传递和引用传递

    C#基础原理拾遗——引用类型的值传递和引用传递 以前写博客不深动,只搭个架子,像做笔记,没有自己的思考,也没什么人来看.这个毛病得改,就从这一篇开始… 最近准备面试,深感基础之重要,奈何我不是计算机科 ...

  2. Hadoop基础原理

    Hadoop基础原理 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 业内有这么一句话说:云计算可能改变了整个传统IT产业的基础架构,而大数据处理,尤其像Hadoop组件这样的技术出 ...

  3. APPcrawler基础原理解析及使用

    一.背景 一年前,我们一直在用monkey进行Android 的稳定性测试 ,主要目的就是为了测试app 是否会产生Crash,是否会有ANR,页面错误等问题,在monkey测试过程中,实现了脱离Ca ...

  4. I2C 基础原理详解

    今天来学习下I2C通信~ I2C(Inter-Intergrated Circuit)指的是 IC(Intergrated Circuit)之间的(Inter) 通信方式.如上图所以有很多的周边设备都 ...

  5. OpenStack的基础原理

    OpenStack的基础原理 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任.   OpenStack既是一个社区,也是一个项目和一个开源软件,它提供了一个部署云的操作平台或工具集.其 ...

  6. JVM 启动参数及原理 转

    Java虚拟机(JVM)是Java应用的运行环境,从一般意义上来讲,JVM是通过规范来定义的一个虚拟的计算机,被设计用来解释执行从Java源码编译而来的字节码.更通俗地说,JVM是指对这个规范的具体实 ...

  7. DNS服务基础原理介绍

    FQDN 全称域名 localhost(主机名或者是别名).localdomain(域名)    FQDN=主机名.域名 根域               . 顶级域名       .com   .n ...

  8. Sql注入基础原理介绍

    说明:文章所有内容均截选自实验楼教程[Sql注入基础原理介绍]~ 实验原理 Sql 注入攻击是通过将恶意的 Sql 查询或添加语句插入到应用的输入参数中,再在后台 Sql 服务器上解析执行进行的攻击, ...

  9. Linux基础知识与基础命令

    Linux基础知识与基础命令 系统目录 Linux只有一个根目录,没有盘符的概念,文件目录是一个倒立的树形结构. 常用的目录功能 bin 与程序相关的文件 boot 与系统启动相关 cdrom 与Li ...

随机推荐

  1. 机器学习中规范化项:L1和L2

    规范化(Regularization) 机器学习中几乎都可以看到损失函数后面会添加一个额外项,常用的额外项一般有两种,一般英文称作ℓ1-norm和ℓ2-norm,中文称作L1正则化和L2正则化,或者L ...

  2. CSS选择器详解(一)常用选择器

    目录 类型选择器 类选择器 ID选择器 伪类 伪元素 类型选择器 通过类型选择器可以选择某一类型的html标签,并对其使用样式. 语法: selector {property1: value; pro ...

  3. 微信公众号H5支付

    微信支付说明1.统一下单接口 统一支付接口: url: https://api.mch.weixin.qq.com/pay/unifiedorder 目的:通过此接口来创建预支付订单,获取订单支付需要 ...

  4. 在LaTeX中配置西夏文字体与环境

    目录 1 配置字族 2 粗体.斜体设定 3 文本编辑器的字体设定(以Sublime Text为例) 4 附录:一些字体的下载源 警告:这篇文章的部分内容需要西夏文字体才能正常显示.若您需要安装,可参考 ...

  5. 【转】marquee标签简介

    本文转自:http://www.360doc.com/content/12/0818/16/8351655_230872993.shtml marquee语法    <marquee>&l ...

  6. Linux中Redis的安装

    一.下载redis redis官网地址:http://www.redis.io/ 下载地址:http://download.redis.io/releases/ redis中文文档地址:http:// ...

  7. c#基础学习(0806)之抽象类实现多态

    首先,要判断是否使用抽象类,可以从下面两个方面进行判断: 1.是不是需要被实例化 2.父类中有没有默认的实现 如果不需要被实例化,父类中没有默认的实现,则用抽象类(否则用虚方法来实现) 下面举个简单的 ...

  8. java之Lombok

    Lombok是一个可以通过简单的注解形式来帮助我们简化消除一些必须有但显得很臃肿的Java代码的工具,通过使用对应的注解,可以在编译源码的时候生成对应的方法 pom依赖: <dependency ...

  9. js如何判断IE浏览器的版本包括IE11

    IE浏览器真是个坑:从ie6以及以前IE版本,简直就是垃圾,不按照Mozilla国际组织的标准来,乱搞.搞得兼容性很差:   <script type="text/javascript ...

  10. 2 duplicate symbols for architecture“文件冲突”

      我在配置第三方库拷贝示例文件中的库文件到新项目完成相关配置之后报下面的错误:   错误的原因是在解决问题之后发现的(第三方库的项目示例demo中的 要拷贝到自己项目中的库  并不需要全部添加到自己 ...