欲望就像拥塞控制,控制不住,那就只能重新再来。
1.用到后
5种:main所在类,new,反射,子类,静态属性或方法。
2.加载器
启动(JAVA_HOME/lib
),扩展(JAVA_HOME/lib/ext
),应用(CLASS_PATH
)
默认实现
- 惰性加载(用到才加载)
-
传递性(a用到b,那加载b就用a的加载器)
jndi
(配置在文件,开发运维解耦;根包定义接口,实现在各厂商。)
接口在JAVA_HOME/lib
,而spi接口的实现是在CLASS_PATH
下,就用到了ThreadContextClassLoader
来打破传递性。 -
双亲委派 (启动- 扩展- 应用 顺序来加载,不会重复加载)
打破双亲委派自定义加载器如tomcat,实现隔离。
通过重写加载器,还可以实现热加载(jsp刷新不用重启。热部署:自动打包重启)。
3.后端编译器(jit)
两种模式:
- client compile
- server compile
优化深入,关注全局
2种检测方法,达到次数编译成机器码提高执行效率:
- 回边计数
执行到}
计数,栈上替换。 - 方法计数
针对方法。
常见的优化方法:
方法内联
,数组边界消除
,逃逸分析
,子表达式消除
4.初始化顺序
5.GC
过程
- new -> 新生区
- 新生区满了 -> 幸存区1
- 新生区又满了 -> 幸存区2
- 年满15-> 老年区
常用GC计数
引用计数(python php 循环引用),可达性分析(java c#)
GC root
栈 方法区 本地方法区
4中引用
强(不GC) 软(ooMGC) 弱(直接GC) 虚(直接GC 存放队列,可回收前做一些事情)
回收器
- serial(单) parNew(多)
- parallel(吞度量1.7 1.8)
- G1(兼并 1.9,新老物理内存合并)
- cms
回收器CMS(并发标记清除)
-
清除过程
单线程标记
简单的对gcroot直接引用的对象进行记录,期间会STW。
并发标记
对gcroot进行所有对象的扫描,耗时最长但是不会STW,期间标记之后的对象状态可能会发生变化,所以需要重新标记。
标记是用的 三色标记法增量更新。 三色标记法是把对象分为白灰黑,3种颜色,开始都是白色,被引用标记为灰色,灰色上的引用都标记完,灰色变黑色,最后只留白色和黑色,白色被回收。
期间不停止用户线程,所以会有2种问题,该回收的没回收,不该回收的回收了。针对第一个问题就是浮动垃圾问题,下一次回收就可以了。第二个问题,就比较严重了,产生第二个问题有两个必要条件:1.节点与灰色的引用被删。2.节点又与黑色节点创建了引用。
增量更新就是记录期间添加的记录,在从黑色节点重新扫描,打破了第二点。
原始快照是G1用的方法,会对被删除的引用记录,走快照的结果,打破了第一点。
重新标记
对上一步标记的对象进行修正。期间会STW。
并发清理 -
缺点:
CPU资源问题:CPU使用较强,容易抢多服务CPU资源。
浮动垃圾问题:产生的浮动垃圾无法处理,如在并发标记与并发阶段中又产生垃圾那么只能等到下次GC再进行处理。
空间碎片问题:由于使用的标记-清除算法,因此在回收结束的时候会产生空间碎片问题,但是可以通过参数设置来解决,不过会消耗点性能。
concurrent mode failure问题:在并发标记或并发清理阶段的时候,如果又触发了垃圾回收,但是本次垃圾回收又没进行完,那么则会触发concurrent mode failure,这时候则会进入到单线程收集,先stop the world,随后使用上文提到的serial old垃圾回收器来进行回收。 -
相关参数
XX:+UseCMSCompactAtFullCollection
: 可以让jvm在执行完标记清除后再做整理,解决上文提到的空间碎片问题,类似使用标记-整理算法。
-XX:ConcGCThreads
:设置GC的时候并发线程数
-XX:CMSInitiatingOccupancyFraction
: 老年大使用百分比达到该值的时候会触发垃圾回收(默认是92)
-XX:+CMSParallellnitialMarkEnabled
:表示在初始标记的时候多线程执行,缩短STW。
-XX:+CMSParallelRemarkEnabled
:在重新标记的时候多线程执行,缩短STW。 -
暂停安全
循环末尾,方法末尾,抛异常。
回收算法
- 标记清理标记然后清理。(老年代cms+g1)
- 标记复制标记完,剩下的进行复制,原来内存直接清除。(新生代)
- 标记整理在标记清理的基础上进行整理。(老年代)
内存泄漏
ThreadLocal
的value手动释放。
单例,方法区引用的。
io资源,lock,close释放。
GC测试
打印GC信息:-XX:+PrintGC -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC
byte[] placeHolder = new byte[64 * 1024 * 1024];
//placeHolder = null;
System.gc();
//第2行注释:[Full GC (System.gc()) 67386K->67199K(125952K), 0.0151228 secs]
//第2行不注释:[Full GC (System.gc()) 67370K->1662K(125952K), 0.0065968 secs]
byte[] placeHolder = new byte[64 * 1024 * 1024];
TestGC testGC = new TestGC(placeHolder);
placeHolder = null;
//testGC = null;
System.gc();
//第4行注释:[Full GC (System.gc()) 67386K->67199K(125952K), 0.0151228 secs]
//第4行不注释:[Full GC (System.gc()) 67370K->1662K(125952K), 0.0065968 secs]
Object a= new Object(); b = new B(a); a=null; //Obect内存并不能释放
网友评论