JVM
为什么要学习Jvm,学习Jvm可以干什么?
jvm为程序分配内存
JVM、JRE、JDK关系
JDK包含Jre、jre包含Jvm
jdk除jre、jvm外,还包含编译文件和对jvm信息进行监控
jre用来运行的基础环境,jvm编译class为文件,适配各操作系统
JVM运行时数据层区分?
方法区:用于存放类信息、常量、静态变量以及编译后的代码。
堆(唯一作用):用于存放对象实例。
程序计数器(线程计数器):用来记录线程当前执行的行号,程序计数器之间互不影响。
本地方法栈:为虚拟机执行方法提供服务(C、C++代码)
虚拟机栈:生命周期同线程,一个方法绑定一个栈帧,栈帧存放局部变量、操作数栈、动态链接、出口。
能手动回收垃圾?
不能,能建议jvm进行垃圾回收,但是不能控制jvm何时进行垃圾回收
堆被分为新生代和老年代?
新生代:老年代=1:2
Eden:From Survivor:ToSurvivor=8:1:1
JVM 每次只会使用 Eden 和其中的一块 Survivor 区域来为对象服务,所以无论什么时候,总是有一块 Survivor 区域是空闲着的。
Minor GC、Major GC、Full GC区别及触发条件?
- Minor GC新生代GC,用来回收新生代
触发条件:Eden区域满了或者新的新生代所需空间大于Eden现有空间
- Major GC老年代GC,用来回收老年代
存活的新生代占用空间>老年代剩余空间
老年代空间满了
晋升老年代的新生代对象所需空间的平均大小>老年代剩余空间
执行system.gc()
CMS GC异常
堆内存分配很大的对象
怎么判断对象存活?
- 引用计数法
- 可达性分析
- 标记-清除法
- 标记-整理法
- 复制法
- 分代算法
- 新生代用复制
- 老生代用标记-清除法和标记整理法
什么是垃圾收集器?
Serial:复制法(单线程)
ParNew:复制法(多线程)
Parallel Scavenge:复制法(可控制吞吐量)
CMS:标记清除算法
Serial Old:标记-整理法(单线程)
Parallel Old:标记-整理法(多线程)
G1(复制法和标记-整理法):优化后的标记-清除法,可以同时作用与老年代和新生代,适用大内存、多处理器机器
- 搭配
JVM参数配置
#常用的设置
-Xms:初始堆大小,JVM 启动的时候,给定堆空间大小。
-Xmx:最大堆大小,JVM 运行过程中,如果初始堆空间不足的时候,最大可以扩展到多少。
-Xmn:设置堆中年轻代大小。整个堆大小=年轻代大小+年老代大小+持久代大小。
-XX:NewSize=n 设置年轻代初始化大小大小
-XX:MaxNewSize=n 设置年轻代最大值
-XX:NewRatio=n 设置年轻代和年老代的比值。如: -XX:NewRatio=3,表示年轻代与年老代比值为 1:3,年轻代占整个年轻代+年老代和的 1/4
-XX:SurvivorRatio=n 年轻代中 Eden 区与两个 Survivor 区的比值。注意 Survivor 区有两个。8表示两个Survivor :eden=2:8 ,即一个Survivor占年轻代的1/10,默认就为8
-Xss:设置每个线程的堆栈大小。JDK5后每个线程 Java 栈大小为 1M,以前每个线程堆栈大小为 256K。
-XX:ThreadStackSize=n 线程堆栈大小
-XX:PermSize=n 设置持久代初始值
-XX:MaxPermSize=n 设置持久代大小
-XX:MaxTenuringThreshold=n 设置年轻带垃圾对象最大年龄。如果设置为 0 的话,则年轻代对象不经过 Survivor 区,直接进入年老代。
#下面是一些不常用的
-XX:LargePageSizeInBytes=n 设置堆内存的内存页大小
-XX:+UseFastAccessorMethods 优化原始类型的getter方法性能
-XX:+DisableExplicitGC 禁止在运行期显式地调用System.gc(),默认启用
-XX:+AggressiveOpts 是否启用JVM开发团队最新的调优成果。例如编译优化,偏向锁,并行年老代收集等,jdk6纸之后默认启动
-XX:+UseBiasedLocking 是否启用偏向锁,JDK6默认启用
-Xnoclassgc 是否禁用垃圾回收
-XX:+UseThreadPriorities 使用本地线程的优先级,默认启用
等等等......
JVM的GC收集器设置
-XX:+UseSerialGC:设置串行收集器,年轻带收集器
-XX:+UseParNewGC:设置年轻代为并行收集。可与 CMS 收集同时使用。JDK5.0 以上,JVM 会根据系统配置自行设置,所以无需再设置此值。
-XX:+UseParallelGC:设置并行收集器,目标是目标是达到可控制的吞吐量
-XX:+UseParallelOldGC:设置并行年老代收集器,JDK6.0 支持对年老代并行收集。
-XX:+UseConcMarkSweepGC:设置年老代并发收集器
-XX:+UseG1GC:设置 G1 收集器,JDK1.9默认垃圾收集器
类加载器
启动类加载器(BootStrap)
加载Java_home/jre/lib/rt.jar下的的所有类
拓展类加载器(ExtClassLoader)
加载Java_home/bin/ext下的类库
系统类加载器(AppClassLoader)
父类加载器为ExtClassLoader
自定义加载器()
父类加载器为AppClassLoader
双亲委派机制
**原理:**双亲委派机制,其工作原理的是,如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行,如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器,如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派模式,即每个儿子都很懒,每次有活就丢给父亲去干,直到父亲说这件事我也干不了时,儿子自己才想办法去完成。
**优势:**采用双亲委派模式的是好处是Java类随着它的类加载器一起具备了一种带有优先级的层次关系,通过这种层级关可以避免类的重复加载,当父亲已经加载了该类时,就没有必要子ClassLoader再加载一次。其次是考虑到安全因素,java核心api中定义类型不会被随意替换,假设通过网络传递一个名为java.lang.Integer的类,通过双亲委托模式传递到启动类加载器,而启动类加载器在核心Java API发现这个名字的类,发现该类已被加载,并不会重新加载网络传递的过来的java.lang.Integer,而直接返回已加载过的Integer.class,这样便可以防止核心API库被随意篡改。
到安全因素,java核心api中定义类型不会被随意替换,假设通过网络传递一个名为java.lang.Integer的类,通过双亲委托模式传递到启动类加载器,而启动类加载器在核心Java API发现这个名字的类,发现该类已被加载,并不会重新加载网络传递的过来的java.lang.Integer,而直接返回已加载过的Integer.class,这样便可以防止核心API库被随意篡改。