• JVM复习


    1.   JVM虚拟机的启动
    2. JVM虚拟机的执行
      虚拟机指令
    //编辑Java文件 虚拟机指令
    javap -v 类名.class
    //查看程序执行  进程
    jps
     
    

      

    简略版jvm虚拟机

    3.JVM 虚拟机的 栈 特点
    跨平台性、指令集小、指令多;职能g'xing
    

      

    4.加载器

      4.1系统加载器
            java的核心类库,使用系统加载器
        4.2引导类加载器
            获取 加载器时为null
        4.3自定义加载器
            什么样的文件加载什么样的文件
    

      

     5.双亲委派机制

    jvm对calss文件 ,是一个按需加载机制。什么时候需要什么时候加载

    自定义加载器 → 系统类加载器 → 扩展类加载器 → 引导类加载器

      

    6.反向委派机制

    加载第三方类的时候   核心类提供接口 → 执行引导类加载  → 线程上下文加载器(默认执行:系统类加载器) →  执行第三方jar包
    优势:
        1.避免类的重复加载
        2.保护程序安全,防止核心api被篡改
    

      

    7.运行时数据区

        7.1程序计数器 (pc寄存器)  (可以理解为 游标或者 迭代器)
               作用:来储存下一条指令 地址的  (占内存空间很小)
                特点:属于线程私有,生命周期与线程保持一致。
                            程序的  分支、循环、跳转、异常处理、线程回复,都需要他来执行。
                            jvm唯一个没有内存溢出 的 区域。
         7.2 为什么使用pc寄存器 储存字节码指令??
                答:因为cpu需要不停切换各个线程,当他切换到要执行线程时,就时候需要jvm的字节码解释器 通过 pc寄存器的值来明确下一条指令。
        7.3pc寄存器为什么设定为线程私有?
                为了能准确地记录各个线程正在执行的字节码指令地址,最好的方法自然是每个线程分配一个pc寄存器。独立计算,不会出现干扰。
        7.4 栈管运行堆管存储
        7.5 栈中常见异常
            1.StackOverFlowError  (如果 jvm虚拟机设置了 固定的栈大小,当运行程序超出,设置的大小就会报StackOverFlowError (栈空间溢出))
            2.OutOfMemoryError (如果jvm虚拟机栈可以动态扩展,但是扩展时无法申请到足够的内存,或者创建创建虚拟机栈,没有足够的内存,就会报OutOfMemoryError)
    

      

    8.虚拟机栈(栈管运行,队管存储)

      8.1 java虚拟机栈,其内部保存一个个栈帧(Stack Frame)(栈帧是栈的最小储存单元)
    一个线程对应一个java虚拟机栈   (栈不存在垃圾回收问题, 但是存在内存溢出)
    栈:  先进后出
    队列:先进先出
    8.2 栈中储存 一个线程对应一个java虚拟机栈 每个方法队形一个栈帧
    8.3栈的内部结构 局部变量表 局部变量表中的变量只在当前方法调用中有效。 当方法调用结束后,随着方法栈的销毁,局部变量表也会随之销毁。 局部变量表 会存放方法的变量, //在静态方法当中,不允许引用this。原因:this变量不存在当前变量表中 //实例方法中可以引用this, 实例对象提供this变量的Slot访问索引 操作数栈 入栈/出栈 方法返回地址 动态链接 一些附加信息 帧数据区(方法返回地址、动态链接、一些附加信息)
    8.4 栈顶缓存技术(hotspot虚拟机) 8.5方法区 方法区是一个非常重要的区域,也是被线程共享的区域,方法区存储了每个类的信息(类的名称、方法信息、字段信息),静态变量、常量以及编译后的代码等。 方法区还包括一个常量池,用来存储编译期间生成的字面量和符号引用。这部分内容在类被加载后,都会存储到方法区中的RCP。值得注意的是,运行时产生的新常量也可以被放入常量池中,比如 String 类中的 intern() 方法产生的常量。 常量池就是这个类型用到的常量的一个有序集合。包括直接常量(基本类型,String)和对其他类型、方法、字段的符号引用.
    8.5.1常量池作用 常量池的作用:就是为了提供一些符号和常量,便于指令的识别。(高可用,使得编译文件较小) 本地方法接口(本地方法库) //java虚拟机 需要调用C库,所存在一些方法 本地方法接口:包括对操作系统对接 本地方法栈 java虚拟机用于管理java方法的调用 本地方法栈,是私有的。

      

    回顾
    方法 -- > 栈帧 -->    局部变量
                            -->    方法返回地址
                            -->    操作数栈
                            -->    动态链接
                            -->    一些附加信息
    

      

    面试问题

    1.栈溢出的情况(stackOverflowError)
        答:设置栈大小,运行时超出设置值
            //不设置栈大小,运行时超出物理内存值    (内存溢出)
    3.栈余越大越好么???
        答:他会挤占运行时区 其他区域的空间
    

      2.垃圾回收会涉及虚拟机栈么?  答案:如以下表格

     
    GC
    Error
    程序计数器
    ×
    ×
    虚拟机栈
    ×
    本地方法区
    ×
    方法区

    什么是TLAB
    
    //
    1.一个进程对应一个方法区和堆。
    2.将堆内存分成小块,每个线程占用一小块内存堆。就形成了TLAB。
    3.方法结束后,堆中对象不会马上转移,
    

      关系图

    堆空间的内部结构
    
    java7 以及之前堆内存逻辑分为三部分:新生区+养老区+永久区
    

      

    java8和之后版本 内存逻辑分为:新生区+养老区+原空间
    相较于以前版本,永久区 变为 原空间

    设置堆空间的大小
    -Xms    表示堆起始内存
    -Xmx    表示堆区的最大内存
    //堆的OOM

      

    年轻代和老年代

     优先在伊甸园区分配,

    堆内存 --> 年轻代 --> 伊甸园、S0、S1的对象分配
    YGC过程,伊甸园区空间充满时,会触发YGC
    常见调优工具

    Minor GC、Major GC、Full GC

    (jvm调优 可简单的理解为 执行GC次数少一些)
    Minor GC 完全等价与  YGC(年轻代)
    老年代区域 执行  Major GC
    Full GC :整个java堆,方法区的垃圾收集
    Major 和 Full GC 执行时间 相较于 Minor GC时间较长
    JVM进行GC,并非每次都是对三个内存区域一起回收,大部分时候回收是 指新生代。(三部分指:新生代、老年代、方法区)
    
    年轻代触发机制(Minor GC)
    1.当年轻代空间不足,就会触发Minor GC(年轻代中 Edem区满了,才会触发GC。 S1,S0不会触发GC)
    2.Minor GC 触发频率高
    3.Minor GC 会触发STW(停止其他用户线程),等垃圾回收结束,才会继续执行。
    
    老年代GC(Major GC/Full GC)
    1.当对象从老年代中消失,Major GC 或 Full GC 执行发生了
    2.执行Major GC 经常会执行Minor GC(非绝对),(当老年代空间不足则先触发Minor GC,如果还是不足则触发Major GC)
    3.Major GC的速度会很慢,STW的时间会很长。
    4.Major GC之后空间还是不足,就会抛出异常(OOM)内存溢出
    
    触发Full GC的五种情况
    1.调用System.gc(),系统建议执行Full GC。(非必然执行)
    2.老年代空间不足
    3.方法区空间不足
    4.通过Miner GC后进入老年代的平均大小大于老年代的空用内存(标记 没理解)
    5.当创建对象Eden区空间不足,转移到S0,S1同样出现空间不足,直接晋升到老年代,老年代空间不足就触发Full GC
    
    //打印GC在虚拟机中的指令
    -Xms9m -Xmx9m -XX:+PrintGCDetails
    
    字符串常量池存在堆空间
    
    针对不同年龄的对象分配原则:
    1.优先分配Eden区
    2.大对象直接分配到老年代(尽量避免出现大对象)
    3.长期存活的对象分配到老年代
    
    堆空间参数设置
    -XX:+PrintFlagsInitial : 查看所有默认参数的初始值
    -XX:+PrintFlagFinal : 查看所有参数的最终值
    -Xms: 初始堆空间内存(默认是物理内存的1/64)
    -Xmx: 最大堆空间内存(默认是物理内存的1/4)
    -Xmn: 设置新生代的大小。(初始值)
    -XX:NewRatio: 配置新生代与老年代在堆结构的占比
    -XX:SurvivorRatio: 设置新生代中Eden和S0/S1空间的比例
    -XX:MaxTenuringThreshould: 设置新生代垃圾的最大年龄
    -XX:PrintGCDetails: 输出详细的GC处理日志
    -XX:HandlePromotionFailure:是否设置控件分配担保
    

      

    代码优化
    1.栈上分配:将堆分配。在方法new出对象,并返回结果。
    -Xms256m -Xmx256m -XX:DoEscapeAnalysis -XX:+PrintGCDetails
    
    2.同步省略
    3.分离对象或标量替换
    

      

  • 相关阅读:
    Easyui datagrid 修改分页组件的分页提示信息为中文
    Easyui datagrid 实现表格记录拖拽
    Java:内部类
    算法导论:Trie字典树
    算法导论:找零钱问题
    lintcode:组成最大的数
    lintcode:验证二叉查找树
    lintcode:将二叉查找树转换成双链表
    lintcode:二叉树的路径和
    lintcode:字符串置换
  • 原文地址:https://www.cnblogs.com/money131/p/13875447.html
Copyright © 2020-2023  润新知