JVM闲散笔记


这篇文章记录我学习JVM当中做的一些笔记,比较杂乱,但比较有价值(哈哈,不要脸如我)

write once,run everywhere

程序计数器:指向当前线程正在执行的字节码指令的地址–行号

为毛需要它?想想CPU,想要去CPU运行,先要得到它的时间片,这是抢占式的,如果没有程序计数器,我下次来的时候,从哪儿开始运行?

虚拟机栈:存储当前线程运行方法所需要的数据,指令,返回地址

运行时数据区:方法区+Heap(数据),程序计数器+虚拟机栈+本地方法栈(指令)

怎么理解这个运行时数据区?就想象人喝水,喝的水会转化成水分子blabla。。。Java类变成class文件以后,要被虚拟机加载,当然也是被拆成一块一块的咯

虚拟机栈–》栈帧–》动态链接?这是个什么玩意儿?—-类似于运行时多态,private Service service;这个Service的实现类有很多,那运行时方法怎么找,那就看存在这个动态连接当中的地址信息了。。。牵强。。

方法区:类信息,常量,静态变量,JIT

一般认为volatile的性能比锁性能好(不绝对) 使用volatile的条件是;语义是否满足应用

可见性:一个线程修改了变量,其他线程立即能够知道

保证可见性的方法:

解释执行:读一句执行一句

编译运行(JIT):

trace跟踪参数:

总结:根据实际情况调整新生代和幸存代的大小

​ 官方推荐新生代占堆的3/8

​ 幸存代占新生代的1/10

​ 在OOM时,记得Dump出堆,确保可以排查现场问题

它们表示一个系统可以容纳多少个类型

如果堆空间没有用完也抛出了OOM 有可能是永久区溢出导致的

Java中,GC的对象是堆空间和永久区

古老的垃圾回收算法:引用计数法 难处理循环引用 没有被Java采用

标记-清除算法 两个阶段:标记阶段和清除阶段

标记-压缩算法 适合于存活对象较多的场合,如老年代

复制算法 不适合存活对象较多的场合 两块空间完全相同 每次只用一块 在新生代当中使用

根据不同代的特点,选取合适的收集算法:

可触及性:从根节点可以触及到这个对象

可复活的:一旦所有引用被释放,就是可复活状态 在finalize()当中可能复活该对象 经验:避免使用finalize,操作不慎可能造成错误 它的优先级低,何时被调用,不确定 可以使用try catch finally来替代她

stop the world:Java中一种全局暂停的现象 所有Java代码停止,native代码可以执行,但不能和JVM交互

它多半是由GC引起的,也有其他原因:

stw的危害:长时间服务停止,没有响应 遇到HA系统,可能引起主备切换,严重危害生产环境

串行收集器:最古老 最稳定 效率高 可能会产生较长的停顿

并行收集器:ParNew

并行收集器:Parallel

-XX:MaxGCPauseMills 最大停顿时间 单位毫秒

-XX:GCTimeRatio 垃圾收集时间占总时间的比 默认99 即允许1%的时间做GC

以上两个参数是矛盾的,不可能同时调优

CMS(concurrent marked Sweep )收集器 —并发标记清除 与用户线程一起执行 着重实现了标记的过程

class装载验证流程

加载

链接

  • 验证
  • 准备
  • 解析

初始化 执行类构造器 static 变量 赋值语句 static{}语句 子类的调用前保证父类的先被调用 是线程安全的

加载:

……….

classloader是一个抽象类

classloader可以定制,满足不同的字节码流获取方式,你可以从网络上加载,可以从文件中加载。。。。

classloader负责类装载过程中的加载阶段

自底向上检查类是否已经加载

自顶向下尝试加载类

有个问题,在bootstrap classloader当中可能声明了某个工厂类或者接口,而实现却在app classloader中,要怎么做才能让bootstrap classloader拿到这个实现类的实例对象呢?

解决办法:Thread.setContextClassLoader() 基本思想是,在顶层class loader中传入底层Class loader的实例 他是一个角色,上下文ClassLoader可以突破双亲模式带来的局限性

双亲模式是默认的模式,但不是必须这么做

怎么实现一个热替换的功能,就是动态的更新类信息,不用重启JVM,那就需要用到class loader相关的知识了

Windows性能监控:

Java自带的工具:

从jstack的输出找出死锁

G1垃圾回收器:。。。