jvm基础

1、类加载:


双亲委派机制
加载一个类时要先加载加载器的父类。父类的加载器也会寻找父类的父类进行加载以此类推,直到找到自上层的父类。如果最上层的父类加载器无法加载(找不到)这个类。才会让子类去加载。如果最下层的子类也无法加载会抛出 CclassNotFoundException

常用的类加载器:

#AppClassLoader 加载的类路径 该加载器通常用来加载用户自定义的类
String appClassLoaderLoadPath=System.getProperties("java.class.path");
#ExtClassLoader 加载jar下拓展包的内容(/jre/lib/ext/xx.jar)
String extClassLoaderLoadPath=System.getProperties("java.ext.dirs");
#bootstrapClassLoader 加载加载jdk原生的jar包(/jre/lib/xx.jar)

2、jvm的结构


  • 结构图
    jvm结构图
  • 栈:
    jvm内存空间中的一块,主管程序运行。生命周期和线程同步。是线程私有的一块内存空间。栈空间包含 方法内的局部变量表、操作数、方法出口信息、上一个方法和下一个方法的引用等其他等信息。
    主要存储:八大基本类型+对象引用+实例方法
    栈空间内存模型
  • 方法区:
    方法区是被所有线程共享的,所有字段和方法字节码,以及一些特殊方法,如构造函数,接口代码也定义在此处,所以定义方法的信息也保存在此处。
    包含:静态变量、常量、类信息(构造方法、接口定义)、运行时常量池。
  • 本地方法栈:
    用于运行本地方法的内存空间。

  • 堆在jvm中被所有线程共享。在虚拟机启动时创建,所有实例以及数组都在堆内存上分配空间,java堆可以处理在物理上不连续的空间。但是在逻辑上应该被视为连续的。
    堆被分为永久代(8以后是元空间)+年轻代+老年代。内存调优主要是对堆内存进行调优。
    永久代:称为非堆,方法区在此空间实现
    年轻代: 分为Eden区s区(from区+to区)
    Eden区:对象刚创建就处于该空间内,当空间达到预警值会触发轻gc。存活的对象被移动到from区。
    s区:分为相等的两块区域 from区和to区。Eden区存活的对象会先移动到from区。再次触发gc时,from区对象会移动到to区,并且计数加一,当计数达到最大值后(默认是15)如果依然存活会被移动至old区。
    老年代
    大对象、长时间存在的对象存储的区域。如果该区域剩余空间低于预警阀值会触发重gc(Full GC) 。重GC时会stop the word ! 因此要减少重GC的出现。
    堆内存结构图
  • 程序计数器
    程序计数器是一个记录着当前线程所执行的字节码的行号指示器。

3、gc算法


  • 引用计数法
    给每一个对象一个引用计数器,当有一个地方引用他时,计数器加一,当有一个引用失效时计数器减一,当计数器值为0时,说明该对象不可达。应该被回收
    优点:原理简单。且高效。
    缺点:实现繁琐。每个对象要维护一个指针。指针会占用额外的空间。而且无法解决循环引用的问题。
  • 可达性分析法
    定义一个名为GC Roots的对象作为起点,这个GcRoots可以有多个,从这些节点开始,往下搜索,搜索所经过的路径称为引用链。当一个对象到GC Roots没有经过任何引用链时,则证明此对象是不可用的。可以被GC回收。
    可以被作为gc roots的有:
    1、虚拟机栈(栈桢中的本地变量表)中的引用的对象
    2、方法区中的类静态属性引用的对象
    3、方法区中的常量引用的对象
    4、本地方法栈中JNI(Java Native Interface)的引用的对象
  • 标记清除算法
    先标记出存活的对象。然后清除掉没有标记的对象
    缺点:要进行两次遍历。效率不高。而且会产生内存碎片。
  • 复制算法
    将空间分成相等的两份,所有新进来的对象只放在一边,gc时先遍历标记存活的对象。再把所有存活的对象在另一个空的空间复制一份。然后全部清空当前空间。
    优点:不会产生内存碎片
    缺点:总有一半空间是空着的。空间利用率不高。当大多数对象存活时间都比较长时,效率不高。
  • 标记压缩(整理)算法
    标记清除算法的优化方案。清除后将所有对象移动到一端。不会产生内存碎片。
  • 复制-清除-压缩(整理)
    标记压缩(整理)算法的优化方案。不会每次清除后都去压缩。清除一段时间后才回去压缩空间。
  • 分代收集算法
    针对堆内存不同的区域采用不同的算法。
    年轻代使用复制算法
    老年代使用标记压缩(整理)算法或者标记-清除-压缩算法

4、常用的垃圾处理器

  • Serial收集器
    单线程处理,在gc时,停止其他线程。通过 -XX:+UseParallelGC来启用该处理器。
    优点:简单高效,拥有很高的单线程收集效率
    缺点:收集过程需要暂停所有的线程。
    算法:复制算法
    适用范围:新生代
    应用:client模式下默认的新生代收集器
  • ParNew(并行)收集器
    Serial的多线程版本
    优点:多cpu时比Serial效率高
    缺点:收集过程暂停所有应用程序线程,单cpu时效率比Serial差
    适用范围:新生代
    应用:service模式下虚拟机首选的收集器
  • Parallel Scavenge收集器
    和ParNew收集器类似,更关注系统吞吐量
  • Serial Old收集器
    Serial收集器的老版本。使用的标记整理算法,清除过程也和serial一样
  • Parallel Old处理器
    Parallel Scavenge 的老版本,使用多线程和标记整理算法进行垃圾回收。
  • cms收集器
    cms(concurrent mark sweep )收集器是一种以获取最短回收停顿时间为目标的收集器
    采用的是标记清除算法 整个过程分为四步:
(1) 初始标记 CMS initial Mark  ---------->	标记gc roots 能够关联到的对象----------> stop the word (但是很快)
(2)并发标记 CMS concurrent Mark ---------> 	进行GC Roots Tracing
(3)重新标记 CMS remark ------------------->		修改并发标记因用户程序变动的内容 ---->stop the word 
(4) 并发清除  CMS concurrent sweep 

在整个过程中,并发标记和并发清除,收集器线程可以与用户线程一起工作。所以总体来说CMS收集器的内存回收过程是与用户的线程同步进行的。
优点:并发收集、低停顿
缺点:产生大量内存碎片、并发阶段会降低吞吐量。

  • G1收集器
    G1收集器在jdk7正式作为商用收集器

特点:
并行与并发
分代收集
空间整合,整体上属于“标记整理算法” 不会导致空间碎片
可预测的停顿,(与CMS相比,更先进的地方在于,能够让用户指定一个时间xxms,用于gc的时间不会超过xx毫秒)

使用G1处理器时,Java堆的内存布局,与其他收集器的差别很大,他将整个java堆划分成多个大小相等的独立区域。虽然还保留有新生代和老年代的概念,但是新生代和老年代不再是屋里隔离的了,他们都是一部分区域的集合。

回收步骤

初始标记(Initial Marking) 标记以下GC Roots能够关联的对象,并且修改TAMS的值,需要暂停用户线程
并发标记(Concurrent Marking) 从GC Roots进行可达性分析,找出存活的对象,与用户线程并发执行
最终标记(Final Marking) 修正在并发标记阶段因为用户程序的并发执行导致变动的数据,需暂停用户线程
筛选回收(Live Data Counting and Evacuation) 对各个Region的回收价值和成本进行排序,根据用户所期望的GC停顿时间制定回收计划

拓展、内存溢出的原因


  • 方法区溢出
    • 方法区溢出的原因
    • 方法区溢出解决方案
#错误信息
java.lang.OutOfMemoryError:metaspace
#解决方法
# 增大元空间内存
java -XX:MaxMetaspaceSize=3200m 
# 方法区包括:静态变量常量、类信息(构造方法、接口定义)、运行时常量池。加载过多的类也会引起方法区溢出。方法区的变量不会被回收。
  • 栈空间溢出
    • 栈空间溢出的原因::
#错误信息
java.lang.StackOverflowError
#解决方法
# 增大元空间内存
java -XX:MaxMetaspaceSize=3200m 
# 栈空间包括:方法内的局部变量表、操作数、动态链接、方法出口信息、其他等信息。
# 栈空间溢出原因:方法的递归调用陷入死循环。
  • 堆空间溢出
    • 溢出原因
      1、堆空间设置过小
      2、高并发请求导致大量对象被创建。
      3、内存泄露(?java什么时候会内存泄露)
    • 堆空间优化
      1、提高堆内存
      2、增加新生代对象最大寿命
      3、增加yang区的内存
      3、调整yang区和old区比例。默认是1:2
      4、调整Eden区和s区比例 默认是8:1:1
      5、在设置了-XX:MaxNewSize的情况下,-XX:NewRatio的值会被忽略
#错误信息
java.lang.OutOfMemoryError:java heap space
#设置堆空间初始内存
-Xms256m
#设置堆空间最大内存
-Xmx512m  
#增加新生代对象最大寿命
-XX:MaxTenuringThreshold(默认是15)  
#指定年轻代初始内存和最大内存
-XX:NewSize100m -Xmn:200m或-XX:MaxNewSize200m
#设置新生代Eden区和s区比例默认是8:1:1 下面设置为 6:2:2
-XX:SurvivorRatio=6
#设置老年代和新生代的比例 设置方法同上
-XX:NewRatio

备注 jvm 常用参数

参数含义说明
-XX:CICompilerCount=3最大并行编译数如果设置大于1,虽然编译速度会提高,但是同样影响系统稳定性,会增加JVM崩溃的可能
-XX:InitialHeapSize=100M初始化堆大小简写-Xms100M
-XX:MaxHeapSize=100M最大堆大小简写-Xms100M
-XX:NewSize=20M设置年轻代的大小
-XX:MaxNewSize=50M年轻代最大大小
-XX:OldSize=50M设置老年代大小
-XX:MetaspaceSize=50M设置方法区大小
-XX:MaxMetaspaceSize=50M方法区最大大小
-XX:+UseParallelGC使用UseParallelGC新生代,吞吐量优先
-XX:+UseParallelOldGC使用UseParallelOldGC老年代,吞吐量优先
-XX:+UseConcMarkSweepGC使用CMS老年代,停顿时间优先
-XX:+UseG1GC使用G1GC新生代,老年代,停顿时间优先
-XX:NewRatio新老生代的比值比如-XX:Ratio=4,则表示新生代:老年代=1:4,也就是新生代占整个堆内存的1/5
-XX:SurvivorRatio两个S区和Eden区的比值比如-XX:SurvivorRatio=8,也就是(S0+S1):Eden=2:8,也就是一个S占整个新生代的1/10
-XX:+HeapDumpOnOutOfMemoryError启动堆内存溢出打印当JVM堆内存发生溢出时,也就是OOM,自动生成dump文件
-XX:HeapDumpPath=heap.hprof指定堆内存溢出打印目录表示在当前目录生成一个heap.hprof文件
XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps Xloggc:$CATALINA_HOME/logs/gc.log打印出GC日志可以使用不同的垃圾收集器,对比查看GC情况
-Xss128k设置每个线程的堆栈大小经验值是3000-5000最佳
-XX:MaxTenuringThreshold=6提升年老代的最大临界值默认值为 15
-XX:InitiatingHeapOccupancyPercent启动并发GC周期时堆内存使用占比G1之类的垃圾收集器用它来触发并发GC周期,基于整个堆的使用率,而不只是某一代内存的使用比. 值为 0 则表示”一直执行GC循环”. 默认值为 45.
-XX:G1HeapWastePercent允许的浪费堆空间的占比默认是10%,如果并发标记可回收的空间小于10%,则不会触发MixedGC。
-XX:MaxGCPauseMillis=200msG1最大停顿时间暂停时间不能太小,太小的话就会导致出现G1跟不上垃圾产生的速度。最终退化成Full GC。所以对这个参数的调优是一个持续的过程,逐步调整到最佳状态。
-XX:ConcGCThreads=n并发垃圾收集器使用的线程数量默认值随JVM运行的平台不同而不同
-XX:G1MixedGCLiveThresholdPercent=65混合垃圾回收周期中要包括的旧区域设置占用率阈值默认占用率为 65%
-XX:G1MixedGCCountTarget=8设置标记周期完成后,对存活数据上限为 G1MixedGCLIveThresholdPercent 的旧区域执行混合垃圾回收的目标次数默认8次混合垃圾回收,混合回收的目标是要控制在此目标次数以内
-XX:G1OldCSetRegionThresholdPercent=1描述Mixed GC时,Old Region被加入到CSet中默认情况下,G1只把10%的Old Region加入到CSet中
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值