关于JVM虚拟机 - 学习总结/笔记(浅入)

推荐学习链接 : 点击打开链接  孙华强

JDK 发展
  1.3 Hotspot 作为默认虚拟机
  1.4 基本成型

  1.5 加入 泛型/注解/装箱/枚举/可变参数/ForEach循环
  1.6 脚本语言的支持/JDBC4.0/开放Java编译器的API
  1.7 G1 垃圾回收/动态语言增强/压缩指针/MIO2.0/

  1.8 Lambda表达式 (函数式编程) /语法增强/Java类型注解
 
  HotSpot - 是JVM虚拟机的核心
  将来JVM的核心会在HotSpot的基础上移植JRockit的特性

JVM 规范

  整数表示方式:
  原码 二进制表示 第一位为符号表示(0为正,1为负)
  反码 符号位不动 原码取反
  负数补码 符号位不动 反码+1
  正数补码 和原码相同
  补码的好处就是直接参与运算时的结果就是真实值
 
  查看int型补码
  for int i=0; i<32 i++
  (a & 0x80000000>>>i)>>>(31-i)

Java 中float在内存的存储
  17.625 =
  0-10000011-00011010000000000000000  一共32位
  1位:符号位
  8位:指数位
  23位:有效数位
  符号位 * 2*2(指数位次方) * 有效数位

Java 栈 

  线程独有 先进后出

  保存的内容是一个方法的局部变量/操作数栈/常量池指针
  每次方法调用都会创建一个帧 并进行压栈

//在栈上分配内存
-server -Xmx10m -Xms10m
-XX:+DoEscapeAnalysis -XX:+PrintGC

//在对堆上分配内存
-XX:+DoEsca.....+改为-


在线程运行时不是直接访问JVM的内存去 而是有一个线程的内存与JVM的内存做交互
volatile-起到的作用就是将变量的信息同步带JVM内存
但是 volatile 不能代替锁
一般认为比锁的性能更好
一般用在<语义是否满足条件>

JVM 指令重排
 比如在一个简单赋值的过程中 JVM 会进行一定的赋值先后的调整来优化程序

JVM 配置参数
  Trace跟踪参数
  对GC的跟踪
   -verbose:gc 打开GC跟踪日志
   -XX:+printGC 打印GC日志信息
   //详细信息/时间戳
   -Xloggc:log/gc.log 制定位置输出日志文件

   -XX:+TraceClassLoading 监控类的加载

  (在Eclipse中Run As --> Run Configgurations... --> Arguments --> VM arguments 的文本框中填写)


 堆参数
  -Xmx 最大堆
  -Xms 最小堆 空间(-Xmx256m)


  -内存区---作用---推荐所占比例-

  新生代 --- 处理 --- 3/8
  幸存代 --- 不易过大 --- 1/10
  老年代 --- 尽量少的使用
 
  -XX:+HeapDumpOnOutOfMemoryError -内存溢出时导出堆到文件
  -XX:+HeapDumpPath -导出路径

  永久区的参数分配
    能够容纳多少个类类型 类太多导致内存溢出
 
栈大小分配
  通常只有几百K
  决定函数调用的深度
  每一个线程创建的时候就会分配完空间
  (栈空间太小递归调用时会出现栈溢出)

GC
  针对堆空间和永久区进行回收

  算法 (可达性分析)
    引用计数算法 (没有使用)
      为每一个对象标记数量 引用+1 释放-1 判断引用为0的时间进行回收
      根引用对象标记
      //循环引用难以清除

    标记清楚算法
      标记阶段:通过根节点搜索 标记可达对象与不可达对象
      清除阶段:可达不清楚/不可达清除
      //清除后碎片太多

    标记压缩 (老年代)
      标记 - 存活的对象进行复制到一定区域 清除边界以外的内存

    复制算法 (老年代)
    内存空间分为相等两块 标记 复制到空闲空间 清理所有对象
    //浪费内存空间
    (老年代做担保空间)
    新生空间/复制空间变小/大对象放到老年代 (几次在复制空间中都没有被回收转移到老年代)

分代思想
  新生代 (对象存活少)周期特别短的对象 适合复制算法
  老年代 (对象存活多)周期特别长的对象 适合标记清楚 / 标记压缩算法


怎么判断垃圾对象
  可触及:根节点可以连接到这个对象
  可复活:在锁中被引用
  不可触及:要回收的对象

Stop-The-Word
全局停顿现象
  native代码可以执行但不能与JVM交互
  三种情况产生:
    Dump线程
    死锁检查
    堆Dump


1:给栈帧分配堆内存的两种方式
  1)指针碰撞
    将内存逻辑上分为两边,一边是空闲,一边是在用的,指针指向分界点,当需要分配内存时只要一定指针即可
    一般用在Serial,PaeNew等垃圾回收器中即堆中的新生代中
  2)空闲列表
    在内存不规律的情况下,虚拟机必须维护一个列表,用于记录那些内存时可用的,在需要进行分配的时候就从列表中找到足够大小的空间进行分配,并且更新列表
    一般用在CMS这种基于Mark-Sweep的垃圾回收器即对中的年老区
2:年轻代与年老代
  1)年轻代
    区域被分为一个Eden(伊甸园)区和Survivor(存活区)空间大小为 8:1
    新对象都会在Eden区创建,每次只使用Eden区和一个Survivor区,当这两个区满了之后就会将还存活的对象复制到另一个空白区(MINOR GC)
    BEGIN->将可回收内存复制到空白区(存活区)->清理刚才区域
  2)老年代
    
  每当进行一次复制回收的时候,还在年轻代中存活的对象就会加1岁,默认15岁后就到年老代
  可以通过-XX:MaxTenuringThreshold=15来设置多少岁后进入年老区

3:标记-清除-整理算法
    年老和永久区垃圾收集的方法都是标记-清除-整理算法
    当年老代内存不足的话就会触发垃圾收集,这个回收叫做FULL GC.默认是占用了68%后收集
    可用参数-XX:CMSInitiatingOccupancyFraction=68自行设置。

4:类加载机制
  1)加载 --> 验证/准备/解析 --> 初始化 --> 使用 --> 卸载

    解析阶段不一定会在准备阶段之后就执行,也有可能会在初始化阶段之后,这是为了支持JAVA的动态绑定的特性;(多态)


  2)类加载器
    获得二进制字节流(从CLASS文件获得)
    当一个类加载器收到了类加载的请求,他首先不会尝试自己去加载这个类,而是将这次的请求委派给自己的父类加载器去加载
    如果父类加载器依然不能加载,则继续用父加载器的父加载器去加载(有点拗口)。层层如此,如果都不能加载
    则最终的结果就是到达顶层——启动类加载器Bootstrap ClassLoader。每一层的类加载器都会根据请求所要加载的类去自己应该加载的
    目录中搜索有没有对应的类和查看该类是否已经被加载。如果有,那么该层加载器加载并返回
    如果到达了启动类加载器后还是不能加载,那么就由最初接收到类加载请求的那个类加载器进行加载。

    那么如果我们自己写一个类也叫作String,那么当加载的时候,就会先检查出该类已经被加载了
    所以不再允许其他的加载器重新加载,因此我们自己写的String类也就不能用了,所以我们不能自己写一个叫做String的类。

  3)准备-解析-初始化
    装在之后就是校验 (确保二进制流的合法性) --> 文件格式校验/元数据校验/符号引用校验
    校验之后就是
    准备阶段 --> 为变量分配内存/设置初始值(仅仅针对类变量 全局变量) !设置的是初始默认值
    解析阶段 --> 将符号引用替换为直接引用
    初始化阶段 --> 这个阶段才会执行类中的代码(静态代码)
      这就是为什么静态方法不能调用非静态方法/变量的原因 以及 main 方法为静态的原因

    可以进入初始化阶段的几种情况
    1:当虚拟机启动的时候,虚拟机会初始化包含main方法的那个类。
    2:当初始化一个子类的时候,发现其父类还没有初始化,就会先初始化其父类。
    3:当我们使用反射对类进行调用的时候,如何该类没有进行初始化,就会先初始化。在我们用JDBC的时候,我们经常会看到这样一行代码:
    Class.forName("com.mysql.jdbc.Driver"); 这就是反射调用,加载该类并且初始化。

5:CLASS - 文件
    .class文件是一个由8位二进制构成一个字节的字节码文件,里边的格式都是按照规定好的顺序紧凑的排列在文件中
    在.class文件中,它的数据都是以无符号数和表的形式存储的
    无符号用来描述一些东西-字符串值/索引/数字/数量值
      - 使用u1 u2 u4 u8 来表示1 2 4 8 个字节
    表就是有多个无符号数或者其他的表构成的复合型数据结构


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值