实战JAVA虚拟机笔记

JVM结构

  • 类加载子系统: 类加载子系统加载类后,将类信息放到方法区,除了类信息外还有运行时常量池信息
  • java堆: 堆在启动时建立,存放所有java实例,堆空间所有线程共享
  • 直接内存: NIO会使用直接内存,读写频繁的场合会考虑使用直接内存
  • 垃圾回收系统: 垃圾回收系统会对方法区,java堆和直接内存进行回收
  • java栈: 每个线程都会有一个java栈,启动线程就创建栈,栈保存局部变量,方法参数
  • 本地方法栈: 本地方法栈用于本地方法调用
  • PC寄存器: 每个线程创建一个PC寄存器

新生代: eden区 S0区(from区) S1区(to区)

对象先分配到eden区,在一次新生代后,如果对象还存活则进入S0或者S1区,每经过一次新生代回收,年龄就会加1,当年龄到一定程度后被认为是老年对象,进入老年代
SimpleHeap s1=new SimpleHeap(1);
SimpleHeap s2=new SimpleHeap(2);

  • -Xss 指定线程最大栈空间
  • 局部变量表存在栈中,如果局部变量过多,每一次调用函数会占用更多的栈空间,最终导致嵌套可调用次数减少
  • jdk1.7前参数-XX:MaxPermSize 设置永久区的大小,jdk1.7之后使用-XX:MaxMetaspaceSize 设置元数据区的大小
常用JVM参数
  1. -XX:+PringGC 只要遇到GC就会打印日志,打印详细信息:-XX:PringGCDetails
  2. -XX:+PrintGCTimeStamps 输出GC发生时间
  3. -XX:+PrintPrintGCApplicationConcurrentTime 打印应用程序执行时间
  4. -XX:+PrintGCApplicationStoppedTime 打印应用程序由于GC产生的停顿时间
  5. -XX:+PrintReferenceGC 跟踪软引用,弱引用,虚引用和FinaFinallize队列
  6. -Xloggc:log/gc.log 打印日志到文件
堆参数设置
  1. 一般设置初始堆-Xms和最大堆-Xmx设置相等,有利于减少垃圾回收次数
  2. -Xmn 设置新生代的大小,一般设置为整个堆空间的1/3或1/4
  3. -XX:SurvivorRatio 设置新生代中Eden空间和from/to空间比例关系 eden/from=eden/to
  4. -XX:SurvivorRatio设置后不生效:

原来,在HotSpot VM里,并行系的收集器(UseParallelGC / UseParallelOldGC)默认开启-XX:+UseAdaptiveSizePolicy, 这个配置会在每次Minor GC之后对From和To区进行自适应分配大小,而SurvivorRatio使用默认值8,设置成任何非8的数值都会无效。所以,我这个参数里面的-XX:+UseAdaptiveSizePolicy其实是画蛇添足了

垃圾回收算法

引用计数法, 标记压缩法, 标记清除法, 复制算法, 分代分区算法

  • 新生代: 复制算法
  • 老年代: 标记压缩算法,标记清除算法
  • 软引用: GC未必会回收弱引用对象,当内存资源紧张的时候会回收
  • 弱引用: GC每次发现都会回收
  • 虚引用: 如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收
垃圾回收器
  • 串行收集器
    1. 新生代串行收集器
      • 复制算法
      • 单线程, 独占式, 进行回收的时候所有线程要停止工作 +XX:+UseSerialGC
    2. 老年代串行收集器:
      • 标记压缩算法
      • 较大应用程序会停顿很长时间
      • -XX:+UseSerialGC 新, 老年代都用串行收集器
      • -XX:+UseParNewGC 新生代用并行回收器, 老年代用串行
      • -XX:+UseParallelGC 新生代用ParaParallelGC, 老年代用串行
  • 并行收集器
    1. 新生代ParNew回收器

      • 复制算法
      • 简单地用多线程代替单线程, 程序会停顿
      • -XX:+UseParNewGC 新生代用ParNew,老年代用串行
      • -XX:+UseConcMarkSweepGC 新生代用ParNew, 老年代用CMS
      • -XX:+ParallelGCThreads 指定回收线程数,一般和cpu数量相当
    2. 新生代ParallelGC回收器

      • 复制算法
      • 重要参数:
      • -XX:MaxGCPauseMillis: 最大垃圾收集停顿时间,如果设置得太小,会导致jvm新建一个较小的堆,加多垃圾回收频率,所以不是越小越好
      • -XX:GCTimeRatio: 默认值是19,意思是不超所1%的时间用于垃圾回收
      • -XX:+UseAdaptiveSizeProxy: 打开自适应GC策略,手工调整比较困难的时候,只要设置最大堆, 目标吞吐量, 停顿时间, 让虚拟机自己完成调优
    3. 老年代ParallelOldGC回收器

      • 标记压缩算法
      • -XX:+UseParUseParallelGC 新生代用ParallelGC回收器,老年代用ParallelOldGC回收器
  • CMS收集器
    1. 主要关注系统停顿时间
    2. 使用标记清除算法,多线程垃圾回收器,非独占式
    3. 初始标记(独占), 并发标记, 预清理, 重新标记(独占), 并发清除, 并发重置

    4. 启用CMS垃圾回收器 -XX:+UseConcMarkSweepGC
    5. -XX:CMSSInitiatingOccupancyFraction 指定回收阈值,默认是68,当老年代空间使用率达到68会执行一次回收,如果内存增长快,在CMS过程中已经出现了内存不足情况,这个时候CMS会失败,虚拟机自动启动老年代的串行收集器,让程序停顿,直到垃圾回收完成
    6. 当执行标记清除算法后,会存在不完整的内存碎片,需要用-XX:+UseCMSCompactAtFullCollection设置当进行多少次CMS回收后,进行一次内存压缩
  • G1收集器
    1. 新生代GC, 并发标记周期(初始标记, 根区域扫描, 并发标记, 重新标记, 独占清理, 并发清理阶段), 混合回收(), 需要则进行FullGC
    2. G1会优先回收垃圾比例较高的区域
    3. -XX:+UseG1GC 打开G1收集器开关
    4. -XX:MaxGCPauseMillis 指定目标最大停顿时间
    5. -XX:ParallelGCThreads 设置并行回收时,GC工作线程数量
  • 大对象当Eden空间不够时,会直接进入老年代,但是体积不是太大的对象有可能优先在TLAB中分配
  • 不推荐使用Finalize()原因
性能监控工具
  1. 系统性能监控:top, vmstat 监控内存和cpu, iostat 监控IO
  2. jvm性能监控工具
    jstat -gc 20212 查看各个空间的情况
    jstat -gccause 20212 查看最近GC的原因
    jinfo -flag MaxTenuringThreshold 20212 查看某个参数的设置值,还可以动态开关参数jinfo -flag +PrintGCDetails 20212**
    jmap -histo 20212 > D:aaa.txt 获取对象统计信息
    jmap -dump:format=b,file=D:aa.hprof 20212 生成堆快照,然后用jdk自带工具jvisualvm打开hprof文件可以看到哪个对象很大,帮助定位问题
    jmap -finalizerinfo 20212 查看对象有没有堆积在finalizer队列中
    jstack -l 16016 > D:d.txt 查看死锁原因
分配的堆空间太小


深入理解jvm和jvm基本调优参数 https://blog.csdn.net/zhangcongyi420/article/details/89060802

锁与并发
原文地址:https://www.cnblogs.com/Baronboy/p/13038114.html