关于jvm:JVM入门

2次阅读

共计 3933 个字符,预计需要花费 10 分钟才能阅读完成。

1、JVM 模板

-Xms4096M -Xmx4096M -Xmn3072M -Xss1M  -XX:MetaspaceSize=256M 
-XX:MaxMetaspaceSize=256M -XX:+UseParNewGC -XX:+UseConcMarkSweepGC 
-XX:CMSInitiatingOccupancyFaction=92 -XX:+UseCMSCompactAtFullCollection 
-XX:CMSFullGCsBeforeCompaction=0 -XX:+CMSParallelInitialMarkEnabled 
-XX:+CMSScavengeBeforeRemark -XX:+DisableExplicitGC -XX:+PrintGCDetails -Xloggc:gc.log 
-XX:+HeapDumpOnOutOfMemoryError  -XX:HeapDumpPath=/usr/local/app/oom

年老代
-XX:MaxTenuringThreshold,默认值是 15,多少次垃圾回收进入老年代
动静年龄判断
-XX:PretenureSizeThreshold 大对象,间接进入老年代
S 区放不下
空间调配担保机制,老年代可用空间 > 新生代所有存活对象,yong gc,老年代可用空间 > 历史 yong gc 均匀大小,yong gc,否则 full gc

老年代
-XX:CMSInitiatingOccupancyFraction,大于该值

碎片整顿
-XX:+UseCMSCompactAtFullCollection

执行多少次 Full GC 进行一次内存碎片整顿
-XX:CMSFullGCsBeforeCompaction=0

-XX:+CMSParallelInitialMarkEnabled 初始标记开启多线程并发执行,默认是 true

-XX:+CMSScavengeBeforeRemark 在 CMS 的从新标记阶段之前,先尽量执行一次 young gc(防止大量扫描)

-XX:+DisableExplicitGC 是避免 System.gc()去轻易触发 GC,顶峰状况下,调用 System.gc()会产生 Full GC

-XX:MetaspaceSize 默认 20M,反射 jdk,cglib 动静生成类,举荐 512MB

-Xms -> ms 是 memory start 简称,-Xmx mx 是 memory max 的简称

-XX:+PrintTLAB 加这个参数能够看到 TLAB 的调配,其中 refills 申请 TLAB 次数,slow allocs : 慢速调配的次数

XX:+ExplicitGCInvokesConcurrent 和 -XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses 参数来将 System.gc 的触发类型从 Foreground 改为 Background

CMS GC 共分为 Background 和 Foreground 两种模式,前者就是咱们惯例了解中的并发收集,能够不影响失常的业务线程运行,但 Foreground Collector 却有很大的差别,他会进行一次压缩式 GC。此压缩式 GC 应用的是跟 Serial Old GC 一样的 Lisp2 算法,其应用 Mark-Compact 来做 Full GC,个别称之为 MSC(Mark-Sweep-Compact),它收集的范畴是 Java 堆的 Young 区和 Old 区以及 MetaSpace。由下面的算法章节中咱们晓得 compact 的代价是微小的,那么应用 Foreground Collector 时将会带来十分长的 STW

Java7 之后常量池等字面量(Literal)、类动态变量(Class Static)、符号援用(Symbols Reference)等几项被移到 Heap 中

2、查看 JVM 中的参数

java -XX:+PrintFlagsFinal -version
看 JVM 所有能够设置的参数

3、String.intern()

简略了解就是裁减常量池的一个办法;当一个 String 实例 str 调用 intern()办法时,Java 查找常量池中是否有雷同 Unicode 的字符串常量,
如果有,则返回其援用,如果没有,则在常量池中增加一个 Unicode 等于 str 的字符串并返回它的援用 (所以留神 s1.intern() 是没有用的,须要的是 s1 = s1.intern())

jdk1.7 之后,字符串常量池曾经转移到堆区,常量还是在元数据区中

4、栈内存溢出

栈是线程公有,它的生命周期和线程雷同。每个办法在执行的同时都会创立一个栈帧用于存储局部变量表、操作数栈、动静链接、办法进口等信息,办法调用
的过程就是栈帧入栈和出栈的过程
在 Java 虚拟机标准中,对虚拟机栈定义了两种异样:
1、如果线程申请的栈深度大于虚拟机所容许的深度,将抛出 StackOverflowError 异样
2、如果虚拟机栈能够动静扩大,并且扩大时无奈申请到足够内存,抛出 OutOfMemeoryError 异样
栈对应线程,栈帧对应办法

5、JVM 内存区域

线程共享 : 堆、元数据区
线程私有化 : 虚拟机栈、本地办法栈和程序计数器

元数据空间和永恒代相似,都是对 JVM 标准中办法区的实现。不过元数据空间与永恒代之间最大的区别在于 : 元数据空间并不在虚拟机中,而是应用本地内存。因而,默认状况下,元数据空间的大小仅受本地内存限度

本地办法栈与虚拟机栈施展的作用是相似的,区别是虚拟机栈为虚拟机执行 Java 办法 (也就是字节码) 服务,而本地办法栈为虚拟机适应到的 Native 办法服务

程序计数器 : 以后线程锁执行的字节码的行号指示器,为了线程切换后能复原到正确的执行地位,每个线程都有一个独立的程序计数器,各个线程之间计数器互不影响,独立存储

6、xx.java 文件是怎么加载到 JVM 中的

xx.java -> xx.class -> 类加载器 -> JVM
一个类从加到到应用,个别会经验上面的过程 :
加载 -> 验证 -> 筹备 -> 解析 -> 初始化 -> 应用 -> 卸载
加载 : 全限定查找此类字节码文件,创立一个 Class 对象
验证 : 是否符合规范
筹备 : 动态变量初始化,比如说 public static int flushInterval; 为 0,不蕴含 final 润饰的 static,final 在编译的时候曾经调配了
类变量会调配在办法区中,实例变量是随着对象一起调配到 Java 堆中
解析 : 符号援用变为间接援用
初始化 : 静态方法和动态代码块执行 (比方 MySQL Driver staic 办法向 DriverManager 注册驱动)
什么时候初始化类呢?
1、new 类()
2、Class.forName()
3、classLoader.loadClass

7、类加载器和双亲委派机制

启动类加载器 : lib 包下外围类库,C++ 写
扩大类加载器 : 默认是 jre/lib/ext,能够通过 -Djava.ext.dir 指定
利用类加载器 : ClassPath 环境变量所指定的门路中的类,java -cp 指定 classpath 门路
自定义类加载器
双亲委派机制,从下往上找,防范上层的类加载器把父类的类重写了,比如说 String,沙箱平安机制

第三方包加载形式,反向委派机制,说分明就是外围代码在 rt.jar 中,实现类用户自已定义,比方 SPI,这种状况下咱们就须要一种非凡的类加载器来加载第三方的类库,而线程上下文类加载器(双亲委派的破坏者),就是很好的抉择,Thread.currentThread().getContextClassLoader(),也就是
classpath 中的 jar

Tomcat 类加载器 :
BootstarpClassLoader -> ExtClassLoader -> AppClassLoader -> CommonClassLoader

CommonClassLoader 并行分为 CatalinaClassLoader 和 ShareClassLoader
ShareClassLoader 上面 WepAppClassLoader

CatalinaClassLoader 用于隔离 Tomcat 自身和 Web
ShareClassLoader 实质是两个 Web 利用之间怎么共享类,并且不能反复加载雷同的类

Tomcat 的自定义类加载 WebAppClassLoader 突破了双亲委派机制,它首先本人尝试去加载某个类,如果找不到再代理给父类加载器,其目标是优先加载 Web 利用本人定义的类。具体实现就是从新 ClassLoader 的两个办法:findClass 和 loadClass,loadClass 调用了 findClass 办法

毁坏双亲委派的点在于,findClass 中是优先应用 WebAppClassLoader 来加载,而不是始终双亲委派顺次向上找,找不到再向上找
loadClass 其实还是遵循 启动类加载器、扩大类加载的,没有,应用 WebAppClassLoader,在没有向上找

8、为什么要分代?以及不同代不同的垃圾回收机制?

分代其实为了关联不同的垃圾回收机制,年老代大部分被回收,所以复制算法,存活少,复制活的对象到 S 区,残余间接清理

老年代存活对象多,所以标记 + 革除 + 整顿

9、办法区内会不会进行垃圾回收?

首先该类的所有实例对象都曾经从 Java 堆内存里被回收
其实加载这个类的 ClassLoader 曾经被回收
最初,对该类的 Class 对象没有任何援用

应用 URLClassLoader 进行类加载器,最初进行 URLClassLoader close 办法,通过重写 finalize 打印办法查看是否被回收
最好的形式就是让所有的不论是加载的 clazz,还是 ClassLoader,还是实例化的对象都为 null,而后 close ClassLoader,就必定不会元数据区溢出

正文完
 0