Jvm常识

作者: cefa6a30d1c3 | 来源:发表于2019-07-09 23:12 被阅读0次

    引言: 浅谈理解 若有错欢迎大家及时纠正


    JVM是什么:

    Java Virtual Machine(Java虚拟机)的缩写用来模拟计算单元, 将.class字节码文件转成计算机能够识别的指令

    是一个虚构出来的计算机, 通过实际的计算机来模拟各种计算机的功能
    我们都知道Java的重要特点之一 就是跨平台操作 而这则是 Java虚拟机在执行字节码时,把字节码解释成具体平台上的机器指令执行  一次编译到处执行 ! 爽歪歪
    
    先来思考一个问题 如果给你一个 .class文件 怎么让他运行起来 大体流程如下 ↓
    image.png

    方法区,堆内存,栈内存 这些都不陌生了 但这个类加载器怎么理解呢 ?

    补充
    方法区: 跟堆一样,被所有的线程共享。方法区包含所有的class 和 常量 永远唯一的
    堆内存: 存放所有new出来的对象
    栈内存(虚拟机栈): 具体的一些方法
    

    JVM类加载机制

    image.png
    image.png

    1)Bootstrap ClassLoader

    负责加载$JAVA_HOME中jre/lib/rt.jar里所有的 class,由 C++ 实现,不是 ClassLoader 子类。

    2)Extension ClassLoader

    负责加载Java平台中扩展功能的一些 jar 包,包括$JAVA_HOME中jre/lib/*.jar或-Djava.ext.dirs指定目录下的 jar 包。

    3)App ClassLoader

    负责加载 classpath 中指定的 jar 包及目录中 class。

    4)Custom ClassLoader

    属于应用程序根据自身需要自定义的 ClassLoader,如 Tomcat、jboss 都会根据 J2EE 规范自行实现 ClassLoader。

    类加载器加载顺序

    加载过程中会先检查类是否被已加载,检查顺序是自底向上,从 Custom ClassLoader 到 BootStrap ClassLoader 逐层检查,只要某个 Classloader 已加载就视为已加载此类,保证此类只所有 ClassLoader 加载一次。而加载的顺序是自顶向下,也就是由上层来逐层尝试加载此类。


    image.png
    代码验证
    public class ClassLoaderTest {
        public static void main(String[] args) {
            ClassLoader loader = Thread.currentThread().getContextClassLoader();
            System.out.println(loader);
            System.out.println(loader.getParent());
            System.out.println(loader.getParent().getParent());
        }
    }
    

    在获取ExtClassLoader的父loader的时候出现了null,这是因为Bootstrap Loader(引导类加载器)是用C++语言实现的,找不到一个确定的返回父Loader的方式,于是就返回null。


    image.png

    JVM内存模型

    image.png
    image.png

    方法区

    方法区和java堆一样,是线程共享的区域;

    方法区的作用的就是用来存储:已经被虚拟机加载的类信息、常量、静态变量等

    而且方法区还有另一种叫法:【非堆】,也有人给方法区叫做永久代

    当方法区存储信息过大时候,也就是无法满足内存分配的时候报错。

    4.1.1.1 运行时常量池

    运行时常量池是方法区中的一部分,主要是用来存放程序编译期生成的各种字面量和符号引用,也就是在类加载之后会进入方法区的运行时常量池中存放


    Java堆

    Java堆是Java虚拟机管理内存最大的一块区域;并且Java堆是被所有线程共享的一块内存区域(最大的区域);

    对于堆内存唯一的目的就是用来存放对象实例的,而且几乎所有的对象实例都是堆内存中分配的内存(可能会有一些对象逃逸分析技术会导致对象实例不是在Java堆中进行内存分配的)

    经常会听到一些程序说“调优”,其中调优的95%部分都是在跟Java堆有关系的;

    因为Java堆是垃圾收集器管理的主要区域


    虚拟机栈

    image.png
    程序员经常说“堆栈”,其中的栈就是虚拟机栈,更确切的说,大家谈的栈是虚拟机中的局部变量表部分;

    虚拟机栈描述的是:Java方法执行的内存模型;(说白了就是:虚拟机栈就是用来存储:

    局部变量、操作栈、动态链表、方法出口这些东西;这些东西有个特点:都是线程私有的,所以虚拟机栈是线程私有的

    因为虚拟机栈是私有的,当线程调用某一个方法再到这个方法执行结束;其实就是对应着一个栈帧在虚拟机入栈到出栈的过程;

    对于虚拟机栈可能出现的异常有两种

    1:如果线程请求的栈深度大于虚拟机栈允许的最大深度,报错:StackOverflowError

    (这种错误经常出现在递归操作中,无限制的反复调用方法,最终导致压栈深度超过虚拟机允许的最大深度,就会报错)

    2:java的虚拟机栈可以进行动态扩展,但随着扩展会不断的申请内存,当无法申请足够内存的时候就会报错:OutOfMemoryError

    本地方法栈

    本地方法栈(Native Method Stacks)与虚拟机栈所发挥的作用是非常相似的,其区别不过是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则是**为虚拟机使用到的Native方法服务(比如C语言写的程序和C++写的程序)


    直接内存

    直接内存(Direct Memory)并不是运行时数据区中的部分;但是这块儿往往会被大多数程序员忽略,不小心也会导致OOM的错误;


    原始的socket IO

    这是因为在JDK1.4之前java操作数据过程中使用的IO操作是原始的socket IO

    传统的IO,通过socket的方式发送给服务端,需要干些什么事情:

    1、先把文件读到操作系统的缓存当中

    2、再把操作系统的缓存中内容读到应用中

    3、再从应用的缓存当中读到发送的socket缓存当中

    4、在从socket缓存当中把数据发出去

    总共做了4次的拷贝。


    image.png

    NIO

    NIO比较传统IO的话,系统中的buffer不再需要拷贝给应用了

    而是read buffer 直接拷贝给socket buffer

    我们的应用只需要在两个buffer之间建立一个管道的

    这样省略了两次的copy。速度就快了很多


    image.png

    NIO可以直接使用Native(本地方法栈)函数库直接分配堆外内存,然后通过一个存储在Java堆中的DirectByteBuffer对象作为堆外内存的引用进行操作;

    所以有时候程序员在分配内存时候经常会忽略掉直接内存。导致各个区域的内存总和大于物理内存限制,然后OOM。

    4.2 JVM线程安全

    image.png

    JVM内存溢出

    Java堆溢出

    Java虚拟机栈溢出

    Java方法区溢出

    GC 垃圾回收机制

    image.png
    Java 1.7 版本 使用回收器为   Parallel Scavenge收集器 + CMS 收集器
    Java 1.8 版本 使用回收器 G1
    若不是很清楚  前往链接 [https://www.jianshu.com/p/1bc9a0e552ce](https://www.jianshu.com/p/1bc9a0e552ce)
    

    相关文章

      网友评论

          本文标题:Jvm常识

          本文链接:https://www.haomeiwen.com/subject/xnhqkctx.html