• JVM结构与内部详解


        源代码 .Java文件编译成 . Class 文件,然后进入到类加载器Class Loader,最后由类加载器加载到JVM

    双亲委派机制:保证安全的机制

               1.类加载器收到类加载的请求

               2.将这个请求向上委托给父类加载器去完成,一直向上委托,知道启动类加载器

                 3.启动加载器检查是否能够启动这个类,能加载就结束,使用当前的类加载器,否则抛出异常,通知子类加载器进行加载

                 4.重复步骤   3

              中心思想就是 自身的类不进行加载,让自身类的父类进行加载,这样就会到顶层的类,最后都会到启动类加载器,如果启动类加载器没有这个类不能进行加载,然后再一步一步地向下加载

              这样一来,如果用户代码中自定义了一个全包名和自带的类一样,比如Java.lang.String 的类,就会加载Java本身的String类,而不是自定义的类。

              这样做是为了避免出现过多的重复字节码,避免原始类被覆盖的问题

    如何打破双亲委派机制

            1.在自定义的类加载器中重写loadClass方法,因为ClassLoader中有一段双亲委派的核心代码,用来不断地找类加载器的父类加载器,直到父类加载器为空,如果重写这段代码就可打破机制

            2.使用线程上下文类加载器

              

    Java中的类加载器

    Bootstrap ClassLoader (启动类加载器)

    Bootstrap ClassLoader,启动类加载,默认加载的是jdk\lib目录下jar中诸多类;

    这个路径可以使用 -Xbootclasspath参数指定。

    Extension ClassLoader (扩展类加载器)

    Extension ClassLoader,扩展类加载器,默认加载jdk\lib\ext\目录下jar中诸多类;

    这个路径可以使用 java.ext.dirs系统变量来更改。

    Application ClassLoader (应用程序类加载器)

    Application ClassLoader,应用程序类加载器,负责加载开发人员所编写的诸多类。

    User ClassLoader (自定义类加载器)

    自定义类加载器,当存在上述类加载器解决不了的特殊情况,或存在特殊要求时,可以自行实现类加载逻辑。

                                  

      

     

    Native关键字

          1.凡是带了native关键字的方法,都是Java的作用范围达不到了,要调用底层的C语言的库

            2.被native修饰的方法都会走本地方法栈

            3.调用本地方法接口JNI

            4.JNI的作用:扩展Java的使用,融合不同的编程语言为Java所用,Java诞生的时候C和C++横行,想要立足就必须要有C和C++的方法

            5.它在内存区域中专门开辟了一快标记区域:Native Method Area  本地方法栈,登记 Native 方法

            6.在最终执行时候,通过JNI加载本地方法库中的方法

     

    方法区  Method Area

            1.静态变量,常量,类信息,(构造方法,接口定义)、运行时常量池存在方法区中,但是,实例变量存在堆内存中,与方法区无关

              Static   Final  Class模板  常量池

    栈 Stack

            1.栈内存,主管程序的运行,生命周期和线程同步,线程结束,栈内存也就释放,所以不存在垃圾回收

            2.栈 满了之后就会报  StackOverFlowError   栈内存溢出错误

            3.栈 +  堆  +  方法区 的交互关系   对象实例化的过程

                          

     

                                                          

     

     

    堆 Heap

            Heap,一个JVM只有一个堆内存,堆内存的大小是可以调节的

            类加载器读取文件之后,一般会把什么东西放到堆中?类、方法、常量、变量,保存我们所有引用类型的真实对象

            堆内存还要细分为三个区域  新生区、养老区、永久区 , GC垃圾回收主要发生在伊甸园区和养老区

            假设堆内存满了,OOM,就会 发生堆内存溢出错误

            jdk 1.8 之后永久存储区改名为元空间,并且本质有一些不同

            新生区 :类诞生和成长的地方,甚至是死亡的地方

                其中分为两个部分,伊甸园区  所有的对象都是在伊甸园区new 出来的   和  幸存者区   又分为   0  和  1区(from  和 to)

     

          元空间:这个区域常驻内存的,方法区也就是位于这一部分,用于存放JDK自身携带的Class对象,Interface元数据,存储的是Java运行的一些环境或者类信息,这个区域不存在垃圾回收!当JVM关闭的时候也就释放这个区域的内存。

            一个启动类,如果加载了大量的第三方jar包,或者Tomcat部署了太多的应用,带量动态生成反射类,不断地被加载,知道内存满,就会导致OOM

            元空间的发展历史,在JDK 1.6以及之前的时候叫做永久代,常量池在方法区

                     JDK 1.7   也叫做永久代,但是慢慢的退化,并且已经有了去永久代的想法,常量池在堆中

                     JDK 1.8    没有永久代,取而代之的是元空间,常量池也在元空间中

    下图中所展示的结构,元空间逻辑上是存在的,也是堆的一部分,但是物理上是不存在的,

             

     

    GC 垃圾回收

          JVM在进行GC的时候,并不是对这三个区域统一回收。大部分的回收都是新生代

           GC算法  :  标记清除算法、标记压缩法、复制算法、引用计数器 

                 引用计数器方法,为每一个对象都创建一个引用计数器,每当对象被引用一次,计数器就加一次,最后根据引用次数,清除垃圾,因为每个计数器也有消耗,同时性能很差,所以几乎不用

                                                                             

          1.标记清除算法  : 回收时扫描这些对象,并对活着的对象进行标记,然后清除,对没有标记的对象进行清除

           优点:不需要额外的空间!

           缺点:两次扫描,严重浪费时间,会产生记忆碎片

                      

            2.标记压缩算法 : 是对标记清除算法的优化,在标记清除的基础上,为了防止产生记忆碎片,再次扫描,向一端移动存活的对象,多了一个移动成本

                    

            3.复制算法 :  谁空谁是to   幸存0区和幸存1区 之间的from  和  to  的关系是随着多次GC的过程而不断交换的,简单理解为谁空谁是to

                  1.每次GC 都会将Eden活的对象移到幸存区中,一旦Eden被GC后就会变成空的

                  2.当一个对象经历了15次的GC都还没有死的情况下,就会进入到老年代(养老区)

                   优点:没有内存碎片

                   缺点:浪费了内存空间,有一般空间永远是空 的  to。假设对象100%存活,成本比较高

                  最佳使用场景:对象存活率低,也就是新生代

             

           算法总结:内存效率  : 复制算法 > 标记清除算法  > 标记压缩算法

               内存整齐度  :   复制算法  =  标记压缩   >  标记清除

               内存利用率从   :  标记压缩  =  标记清除  >  复制算法

            没有最好的算法,只有最合适算法   

     

          

     

  • 相关阅读:
    android5.1 修改音量键绑定多媒体声音
    如何使用Android Studio开发/调试Android源码
    git远程从入门到放弃
    java.lang.IllegalStateException: Restarter has not been initialized
    SpringBoot,Vue前后端分离开发首秀
    SpringBoot结合swagger2快速生成简单的接口文档
    SpringBoot整合SpringData JPA入门到入坟
    SpringBoot结合Swagger2自动生成api文档
    uni-app初体验及打包成apk
    Jave Web阿里云短信服务发送验证码
  • 原文地址:https://www.cnblogs.com/2940500426yingxin/p/16119685.html
Copyright © 2020-2023  润新知