1、成熟的系统调优
一、必定要绝对避免循环查数据库和缓存(PS:循环里面就不能有查询缓存,更不能有查询数据库的操做,由于循环的次数无法控制)java
二、对于API接口的话,通常都是直接查缓存的,没有查数据库的算法
三、多用批量查询,少用单条查询,尽可能一次查出来数据库
四、对于使用阿里云,要留意一下相应产品的配置,该花的钱仍是得花,同时,千万要记得正式环境中使用相应产品的内网地址缓存
五、注意链接池大小(包括数据库链接池、Redis缓存链接池、线程池)安全
六、压测的机器上不要部署其它的服务,只跑待压测的服务,避免受其它项目影响;对于线上环境,最好一台机器上只部署一个重要的服务数据结构
七、没有用的以及被注释掉的代码,没有用的依赖最好及时清理掉多线程
八、集群自不用说并发
九、一些监控类的工具工具能够帮助咱们更好的定位问题,好比链路跟踪,此次项目中使用了PinPointjvm
十、若是技术上优化的空间已经很是小了,能够试着从业务上着手,用实际的数听说话,能够从平常的访问量,历史访问量数据来讲服测试工具
十一、每一次代码改动都有可能引入新的问题,所以,每次修改代码后都要回归测试一下(PS:每次修改完之后,我都会用几组不一样的关键词搜索,而后比对修改前和修改后返回的数据是否一致,这个时候postman,以及Beyond compare就派上用场了)
十二、关键的地方必定要多加点儿日志,方便之后排除问题,由于排查线上问题最主要仍是靠日志
2、jvm 各类深刻了解
引用计数算法
主流的Java虚拟机里面没有选用引用计数算法来管理内存,其中最主要的缘由是它很难解决对象之间相互循环引用的问题。
可达性分析
GC roots对象向下搜索,搜索过的路径叫引用链,对象与GC roots 无关联,就被断定为为可回收对象。
java中,可做为GC roots的对象包括:虚拟机栈中引用的对象,方法区中类静态属性引用的对象,方法区中常量引用的对象。方法栈中JNI引用的对象。
强引用就是指在程序代码之中广泛存在的,相似“Object obj=new Object()”这类的引用,只要强引用还存在,垃圾收集器永远不会回收掉被引用的对象。
软引用是用来描述一些还有用但并不是必需的对象。对于软引用关联着的对象,在系统将要发生内存溢出异常以前,将会把这些对象列进回收范围之中进行第二次回收。若是此次回收尚未足够的内存,才会抛出内存溢出异常。在JDK 1.2以后,提供了SoftReference类来实现软引用。
弱引用也是用来描述非必需对象的,可是它的强度比软引用更弱一些,被弱引用关联的对象只能生存到下一次垃圾收集发生以前。当垃圾收集器工做时,不管当前内存是否足够,都会回收掉只被弱引用关联的对象。在JDK 1.2以后,提供了WeakReference类来实现弱引用。
虚引用也称为幽灵引用或者幻影引用,它是最弱的一种引用关系。一个对象是否有虚引用的存在,彻底不会对其生存时间构成影响,也没法经过虚引用来取得一个对象实例。为一个对象设置虚引用关联的惟一目的就是能在这个对象被收集器回收时收到一个系统通知。在JDK 1.2以后,提供了PhantomReference类来实现虚引用。
finalize()方法,能够对处于GC中的对象进行一次拯救,即便是在F-Queue的队列中,只要和任何一个对象创建关联,或是给某个类变量或对象赋值,那就会回到弱引用。固然这样的拯救只有一次,由于finallize()只能被调用一次。
回收方法区(永久代),这里面的方法回收效率比较低,在堆中,尤为新生代,一次回收能够回收大概70%-90%的空间,永久代的垃圾回收效率很低
永久代回收有两部份内容:1.废弃常量和无用的类 2.回收废弃常量(相似于java堆中的对象)。
知足三个条件会被回收:1.该类全部的实例都已经被回收,也就是java堆中不存在该类的任何实例。 2.加载该类的classloader已经被回收。 3.该类对应的java.lang.Class对象没有在任何地方被引用,没法在任何地方经过反射访问该类的方法。
垃圾收集算法:
1.标记清除算法,最起初的收集算法,后续算法都是针对这个算法进行改进获得的。存在的问题:1.效率不高。2.空间问题,大多致使之后程序运行过程当中须要分配大对象时,没法找到足够的内存,致使提早出发垃圾回收。
2.复制算法,把内存划分为大小相同的两块,每次使用一块。当一块内存用完,就将存活对象复制到另外一块,再把已使用的那块清除。 优点:实现简单,运行高效。 缺点:这种算法直接把内存缩小一半,代价过高,当对象存活率较高时要进行较多复制操做,效率会变低。用途:如今商业虚拟机基本都是采用复制算法来回收新生代。
3.标记整理算法:根据老年代的特色,标记整理算法应运而生,过程和标记清楚算法同样,但后续是让全部存货对象向一端移动,而后直接清理其余内存。
4.分代收集算法:当前商业虚拟机都是采用分代回收,根据对象存活周期的不一样将内存划分为几块。通常是把java堆分为新生代老年代,这样就能够根据各年代特色适当的收集算法。新生代-----复制算法,老年代-----标记清理或标记整理。
CMS收集器
HotSpot:实现中使用一组oopmap的数据结构来达到目的,在类被加载的时候,hotspot九八对象内的偏移量上的数据类型计算出来,在编译过程当中,也会在特定的位置记录下栈和寄存器哪些引用。
做用:GC在扫描的时候就得知信息。
安全点: 在hotspot内容变化的时候,并无为每一个指令生成oopmap,只是在特定位置记录这些信息,这些位置就是安全点,程序并非全部地方都停下来GC,只有在安全点位置才能暂停。安全点决定了程序是否具备程序长时间执行的特征。
hotspot虚拟机的垃圾收集器:
7种不一样的分代收集器:
Serial收集器 :jdk1.3.1以前新生代惟一选择.单线程收集器,他在进行垃圾收集时,全部工做县城都须要暂停,直到他收集结束。优势:简单高效,对于单个cpu环境来讲,serial收集器没有其余线程开销,最高单线程收集效率。由于停顿时间能够控制在几十毫秒之内,不频繁发生彻底能够接受,因此知道1.7 Serial收集器仍是client模式下的虚拟机最好选择。
ParNew收集器: 他是Serial收集器的多线程版本。他是许多运行在server模式下的虚拟机首选的新生代收集器。有一个重要缘由,目前只有它与CMS收集器配合工做。
Parallel Scavenge收集器: 新生代收集器,采用复制算法的收集器,并行多线程收集器。PS收集器的目标是达到一个可控制的吞吐量(Throuhtput)。所谓吞吐量就是CPU用于运行用户代码的时间与CPU总消耗时间的比值。PS收集器又被称为吞吐量优先级收集器,它还有一个特别的参数:+UseAdaptiveSizePolicy参数。这个参数打开以后,就不用手动指定新生代大小,eden与survivor区的比例,晋升老年代对象年龄等细微参数。虚拟机会自动调节被称为GC自适应。自适应策略也是PS收集器和ParNew收集器一个重要区别。
Serial Old收集器: 是Serial老年代版本,一样是一个单线程收集器,使用标记整理算法。
Parallel Old收集器: Parallel Scavenge收集器老年版本,使用多线程和标记整理算法。
CMS收集器: 是一种以获取最短回收停顿时间为目的的收集器。但愿停顿时间最短,来得到更好的用户体验。 使用标记清除算法,运做比较复杂,分为4个步骤分别是:初始标记,并发标记,从新标记,并发清除。1.初始标记,仅仅标记一下GC roots关联到的对象,速度很快,并发标记阶段就是进行GC rootsTracing的过程,二从新标记阶段是为了修正并发标记期间因用户程序继续运做而致使标记产生变更的一部分对象的标记记录。优势:并发收集,低停顿,用户体验好。 缺点:1.CMS收集器对CPU资源很是敏感。致使一部分线程被占用,使应用程序变慢,吞吐量下降。2.CMS收集器没法处理浮动垃圾(并发清理阶段用户线程还在运行,这段时间就可能产生新的垃圾,新的垃圾在这次GC没法清除,只能等到下次清理)。3.基于标记清除算法,结束时会产生大量空间碎片垃圾。
G1收集器: 当今收集器技术发展最前沿成果之一。特色:1.并行与并发,经过并发的方式保持java运行不受GC影响。2.分代收集,根据存活时间来获取最好的收集效果。3.空间整合,G1收集器总体来看是基于标记整理算法,局部上来看是基于复制算法,意味着运做期间不会产生内存空间碎片,收集后能提供规整的可用内存。有利于长时间运行,分配大对象时不会由于没法找到连续内存空间而提早GC。4.可预测的停顿,这是比CMS一大优点,能让使用者明确指定在一个长度的时间片内,这几乎已是实时Java的垃圾收集器特征。
内存分配和回收策略:1.对象优先在Eden分配2.大对象直接进入老年代3.长期存活的对象将进入老年代4.动态对象年龄判断5.分配担保