码迷,mamicode.com
首页 > 其他好文 > 详细

JVM 小总结

时间:2020-08-20 18:22:08      阅读:61      评论:0      收藏:0      [点我收藏+]

标签:重复加载   启动   aic   管程   out   dump   不用   园区   快速   

JVM

  • 1、JVM 的位置

    • 运行在操作系统之上的
    • java程序是排在 jre(jvm) 上的
    • 技术图片
    • 技术图片
    • 技术图片
    • 所谓的JVM 调优就是在堆里面调,方法区就是 一个特殊的堆
  • 2、JVM 的体系结构

  • 3、类的加载器

    • 作用
      • 加载 class 文件
      • 技术图片
      • 类加载器分为好几个,有等级
        • 1、虚拟机自带的加载器
        • 2、启动类(根)加载器
        • 3、扩展类加载器
        • 4、应用程序(系统类)加载器
  • 4、双亲委派机制

    • 当某个类加载器需要加载 .class 文件时,它首先把这个任务委托给他们的上级类加载器,递归这个操作,如果上级的类加载器没有加载,自己才会加载这个类

    • 作用:
      • 1、防止重复加载同一个 .class。通过委托去向上面问一问,加载过了,就不用再加载一遍。保证数据安全
      • 2、保证核心 .class 不能被篡改,通过委托方式,不会去篡改核心 .class 。即使篡改也不会去加载,即使加载也不会是同一个 .class 对象了,不同的加载器加载同一个 .class 也不是同一个 Class 对象,这样保证了 Class 执行安全。
    • 技术图片

    • 类加载的过程和使用那个加载器
      • 1、类加载器收到类加载的请求
      • 2、将这个请求向上委托给父类加载器去完成。一直向上委托,直到启动类加载器
      • 3、启动类加载器检查是否能够加载当前这个类,能加载就结束,使用当前的类加载器,否则,跑出异常,通知子加载器进行加载
  • 5、沙箱安全机制

  • 6、Native

    • JNI (本地方法接口) java native interface

      • // native :

        ? 1、凡是带了 native 关键字的,说明 java 的作用范围达不到了,会去调用底层 C 语言的库

        2、会进入本地方法栈,调用 JNI, 调用本地方法库,

        ? JNI 的作用就是扩展 java 的使用,融合不同的语言为 java 所用,最初是 C、C++

        所以在内存中开辟了一块区域,为了登记 native 方法,

        3、调用其他接口其实还可以使用 Socket、WebService、http、rpc 、restful

  • 7、PC 寄存器

    • 程序计数器:Program Counter Register
    • 每个线程都有一个程序计数器,就是一个指针,指向方法区中的字节码(用来存储存储指向像一条指令的地址,也即将要执行的指令代码),在执行引擎读取下一条指令, 是一个非常小的内存空间,几乎可以忽略不计
  • 8、方法区

    • Method Area:

      • 方法区是被所有的线程共享,所有字段和方法字节码,以及一些特殊方法,如构造函数,接口代码也在此定义,简单说,所有定义的方法的信息都保存在该区域,此区域属于共享区间,

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

          说白了就是:

          ? staic、 final、Class、常量池、、、

  • 9、栈

    • 数据结构。栈和队列进行比较

    • 栈:先进后出,后进先出

      • 所以为什么 main 方法最后退出?

        • 栈溢出、递归问题(死循环)、无限压栈 、压栈超过了栈的深度

        • 技术图片

        • 栈:
          • 何时发生栈内存溢出?
            • 对于一台服务器而言,每一个用户请求,都会产生一个线程来处理这个请求,每一个线程对应着一个栈、栈会分配内存,此时如果请求过多,这时候内存就不够了,就会发生内存溢出
          • 什么时候会发生栈溢出 ?
          • 栈溢出是指不断的调用方法,不断的压栈,最终超出了栈允许的栈的深度,最终超出了栈允许的栈深度,就会发生栈溢出,比如递归操作没有终止,死循环

        • 帮助记忆:
          • 可以把内存你做一个大箱子,栈比作一个小箱子,栈溢出是指小箱子装不下了,而栈内存溢出是大箱子在也装不下小箱子了
        • 主管程序的运行,生命周期和线程同步

        • 线程结束,栈内存你就会释放

        • 对于栈来说,没有垃圾回收的问题

        • 栈里面放的东西:

          • 8 大基本类型+ 对象引用 + 实例的方法
        • 栈运行原理:
        • 栈、堆、方法区的交互关系
          • 栈是类模板,堆是对象实例
    • 队列: 先进先出 (FIFO)

  • 10、三种 JVM

    • Sun 公司 HotSpot
    • IBM J9VM
    • BEA JRockit
  • 11、堆

  • 堆的图
  • 技术图片

    • 技术图片
      • 逻辑上存在,物理空间上不一定存在
    • heap、一个 jvm 只有一个堆内存,对内存的大小是可以调节的
  • 12、新生区(伊甸园区)、老年区 、幸存区0, 幸存区1

    • 新生区是类诞生和成长的地方,甚至死亡
    • 多有的对象都是在一点园区new出来的
  • 技术图片

    • GC 垃圾回收,主要是在伊甸园区和老年区

    • 假设内存满了、OOM、java.lang.OutOfMemoryError: java heap space
    • 无限字符串的例子 - 其实也就是无限 new 对象:

      • 技术图片

      • VM 参数调试
      • 技术图片

      • 技术图片

  • 13、永久区

  • 这个区域常驻内存的,用来存放 jdk 自身携带的 Class 对象,Interface 元数据,存储的是 java 运行时的一些环境或类信息,这个区域不存在垃圾回收,关闭虚拟机就会释放这个区域的内存

  • 什么情况下在永久区就崩了呢?
    • 一个启动类加载了大量的第三方 jar 包,tomcat 部署了太多的应用,或者大量动态生成的反射类,不断的被加载,直到内存满了,就出现 OOM
    • jdk1.6之前: 叫永久代,常量池是在方法区

    • jdk1.7: 永久带,但是慢慢的退化了,去永久代,常量池在堆中

    • jdk1.8之后:无永久代,常量池在元空间

    • 在一个项目中,突然出现 OOM 故障,那么该如何排除 - 研究为什么出错?

      • 能够看到代码第几行出错:

        • 内存快照分析工具,MAT、Jprofiler

        • debug: 只能一行行的分析代码

        • MAT、Jprofiler作用

          • 分析 Dump、内存文件,快速定位内存泄漏
          • 获得对中的数据
          • 获得大的对象
  • 14、对内存调优

  • 15、GC (自动垃圾回收机制)

    • 技术图片

    • Jvm 在进行 GC 时,并不是对以下三个区域统一回收,大部分时候,回收都是新生代,

      • 新生代
      • 辛存区( from \ to)
      • 老年区
        • GC 两种类型: 轻GC(普通 GC), 重 GC (全局 GC)
    • GC 的题目 :

      • 1、JVM 的内存模型和分区 - 详细到每个区放什么?

        • 方法区
        • 本地方法栈
        • PC 计数器
      • 2、堆里面的分区有哪些?

        • 新生区(伊甸园)
        • 幸存区(from\ to),谁空谁是 to
        • 老年区
      • 3、GC 的算法有哪些?

        • 标记清除法
        • 标记压缩
        • 复制算法
        • 引用计数器
      • 4、轻 GC 和 重 GC 分别在什么时候发生?

    • 常用算法
      • 技术图片
  • 16、JMM

    • 1、什么是 JMM?
      • Java Memory model Java 内存模型
    • 2、干嘛的?
      • 作用:缓存一致性协议,用于定义数据读写的规则(遵守,找到这个规则)

      • JMM 定义了线程的主内存之间的抽象关系:线程之间的共享变量存储在主内存(Main Memory)中,每个线程都有一个私有的本地内存(Local Memory)

      • 技术图片

      • CPU 中运行的线程从主存中拷贝共享对象 obj 到它的 CPU 缓存,把对象 obj 的 count 变量改为 2,但每个变量对运行在右边 CPU 中的线程不可见,因为这个更改还没有 flush 到主存中,要解决共享对象可见性这个问题,我们可以用 java volilate 关键字或者加锁

      • 技术图片

      • 解决共享对象可见性这个问题: volilate
    • 3、如何学习?

      • ? JMM: 抽象的概念 - 理论

      • 技术图片


  • 17、总结

    • 内存效率:

      • 效率最高: 复制算法 > 标记清除算法 > 标记压缩算法
      • 内存整齐度: 复制算法 = 标记压缩算法 > 标记清除算法
      • 内存利用率: 标记压缩算法 = 标记清除算法 > 赋值算法
    • 思考一下, 难道没有最优的算法吗?

      • 没有,没有最好的算法,只有最合适的算法 --->

      • 分代收集算法
        • 每一代都有不同的算法

        • 年轻代:

          • 存活率低
          • 复制算法
        • 老年代:

          • 区域大: 存活率

          • 标记清除(内存碎片不是太多) + 标记压缩混合 实现

JVM 小总结

标签:重复加载   启动   aic   管程   out   dump   不用   园区   快速   

原文地址:https://www.cnblogs.com/jcjc/p/13520585.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!