Java虚拟机讲解 与 搞垮Java虚拟机

什么是Java

简单概括什么是Java,Java既是一门语言也是一个平台。Java既可以编写C/S,也可以编写B/S模式的软件。语法由Java Language Specification规定。

Java技术体系
接下来让我们看看我们的Java技术体系,从定义上讲,Kotlin、Clojure、JRuby、Groovy等都是运行在Java虚拟机上的编程语言及其相关的程序都属于Java技术体系中的一员。
Java技术体系包括以下几个组成部分:

  • Java程序设计语言
  • 各种硬件平台上的Java虚拟机实现
  • Class文件格式
  • Java类库API
  • 来自商业机构和开源社区的第三方Java类库

Java虚拟机

作为一个开发平台,已JVM为基础。虚拟机内部机制由Java Virtual Machine Specification规定。
JDK是Java开发工具,而JRE才是Java运行时,JRE才是所谓的Java虚拟机。
接下来让我看看Java程序是如何运行的:
在这里插入图片描述

中上所看,我们平常使用的程序都是直接运行在操作系统之上的,而我们的Java程序必须运行在Java虚拟机之上,不能直接运行在操作系统之上。
JVM的启动步骤:

  1. 执行JVM启动器JAVA_HOME/bin/java.exe
  2. 启动器加载JAVA_HOME/jre/bin/server/jvm.dll
    1.jvm.dll检查OS,获取JVM次数
    2.根据参数向OS申请分配内存、创建线程等
  3. BootstrapClassloader加载JAVA_HOME/jre/lib/rt.jar等框架类库
  4. 启动main线程,加载卖弄方法Java类
  5. Java main方法执行

以下是Java虚拟机的两大作用:
1. 跨平台
就因为我们的Java程序不能直接运行在操作系统之上,这样就给我们带来了Java程序是可以跨平台的。我们的Java文件通过JDK编译完成之后变成一个Class文件其中内部就是一些字节码,而我们的CPU并不认识字节码所以无法直接运行,这个时候我们就需要一个中间商那它就是我们的Java虚拟机。
Java虚拟机简单的概括:是一台抽象的计算机,由JVM进程模拟出来,主要负责讲class文件中的字节码解析成CPU认识的指令,然后执行java class文件。Java虚拟机可以在我们任意的操作系统中。
在这里插入图片描述

2. 自动内存管理
在创建对象的时候虚拟机自动给对象分配好内存空间,以及在未使用的时候进行垃圾回收。
Java总体结构

在这里插入图片描述
首先,对于线程来说,方法区(Method Area)、堆(Heap)是公共的,而虚拟机栈(VM Stack)、本地方法栈(Native Method Stack)、程序计数器(Program Counter Register)是私有的。

运行时数据区:Java虚拟机在执行Java程序的过程中会把它所有管理的内存划分为若干个不同的数据区域。这些区域有各种的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而一直存在,有些区域则是依赖用户进程的启动和结束而建立和销毁。

方法区:方法区与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码缓存等数据。

堆:Java中的堆是虚拟机所管理的内存区域中最大的一块。Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放实例对象,Java里面几乎所有实例对象都是在这里进行分配内存。此外Java堆也是垃圾回收器管理的一块内存区域,一般使用的都是GC垃圾回收器。如果在Java堆中没有完成实例分配,并且堆也无法在扩展时,Java虚拟机将会抛出OutOfMemoryError异常。

虚拟机栈:Java虚拟机栈的生命周期与线程相同,虚拟机栈描述的是Java方法执行的线程内存路径,它的一个顺序是后进先出(LIFO):每个方法执行的时候,Java虚拟机都会同步创建一个栈帧用于存储局部变量表、操作数栈、动态连接、方法出口等信息。每一个方法被调用直至执行完毕的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。对于这个内存区域规定了两类异常状况:如果线程请求的栈深度大于虚拟机栈所允许的深度,将抛出StackOverflowError异常;如果Java虚拟机栈容量无法申请到足够的内存会抛出OutOfMemoryError异常。

本地方法栈:本地方法栈与虚拟机栈所发挥的作用非常相同,其中的区别只是虚拟机栈为虚拟机执行Java方法也就是字节码服务,而本地方法栈则是为虚拟机使用到本地的方法服务。与虚拟机栈一样,本地方法栈也会在栈深度溢出或者扩展失败时分别抛出StackOverflowError和OutOfMemoryError异常。

程序计数器:是一块较小的内存空间,它可以看作是当前线程所执行代码的指示器。它是程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。

类加载器的分工
在这里插入图片描述
类加载器设计成这样子的原因是为了防止加载入有会破坏系统内部的类。

如何搞垮Java虚拟机

1. OutOfMemoryError
调整堆内存大小:-Xms64M -Xms65M ---------------------------- 越小越好越能搞垮Java虚拟机,如下图
在这里插入图片描述
在这里插入图片描述

2. StackOverflowError
调整栈内存大小:-Xss124k ---------------------------- 越小越好越能搞垮Java虚拟机,如下图
在这里插入图片描述
在这里插入图片描述
3. OutOfMemoryError : Metaspace 调整方法区大小:-XX:MetaspaceSize=64M -XXMaxMetaspaceSize=128M ---------------------------- 越小越好越能搞垮Java虚拟机