java性能优化

来源:互联网 发布:2016coc双王升级数据 编辑:程序博客网 时间:2024/05/16 13:06

在这里首先要说到的是二八原则,那就是20%的代码和程序设计影响了系统80%的性能,也就是说的话如果我们把代码设计好就可以优化80%的性能。
在优化中又开始分3个层次,基础技术,构架方面,层次方面。

在构架方面就要提到一个就是数据镜像:数据镜像的好处就是可以实现负载均衡,把一个服务器上的数据库压力放在多台上来。也可以达到了复用性和一致性,是解决HA的有效的方法。
(HA)是指尽量的减少银系统维护操作和系统突发情况的所导致的停机的时间,依次来提高程序的可用性。

第二个常用的就是数据的分区:我们可以把数据库进行分区管理,比如不活跃的用户我们单独放在一张表上,活跃的经常修改的我们在单独把它单独的放在一个表上。
上面说到的数据的分区问题一定的程度上是解决了数据的负载压力,但是热点数据的压力依然还是存在的(所谓的热点数据就是指的是具有高访问量的数据),这里还有用到的是镜像,这时候我们需要的是一个分布式系统实现,监视各个站点的负载情况,然后实现我们的均衡负载,这些系统就是我们后面要学习的haddoop和spark。

所谓的分布式存储就是这样的,把数据库的数据放在了不同的电脑上的硬盘上,在nosql中就是把一个集合拆成多条的记录,但是为什么每条记录都是散的,要用的时候是怎么取的了?这个时候就需要的是一个路由器(也是一个应用程序)。负责的是请求和转发。

正如我们所知道的那样,java堆区是一块用于存储对象实例的内存区,当然它也是GC执行垃圾回收的重点区域。正是因为java堆区是gc的重点的回收区域,那么GC极有可能是会在大内存中频繁的使用最后成为了系统性能的瓶颈。这里就要说到我们的阿里巴巴了,他们团队研发的中国首款jvm虚拟机,其中就是把生命周期很长的收集到headp(就是堆)以外去,这样可以提高gc的工作时间也可以提高gc的工作效率。目前世面上主流的算法,都是按照分代继承的,把一个对象按照它的生命周期分为新生代,老年代,这里我只是初步的讲下。

java7开始支持对象的栈分配和逃逸分析的机制。这样的机制除了能讲堆对象转换成为栈对象以外,其实主要还是有其他的两个作用的。
1.同步消除问题
逃逸分析可以让我们知道一个对象是否只是被一个线程所使用,如果是的话我们就可以消除同步保护,这样就可以提高并发和性能。
2.矢量替换
通过逃逸分析我们知道了如果对象的内存存储结构不需要连续存储进行的家,就可以将对象的部分甚至全部都保存在CPU的寄存器中,这样大大提高访问的速度。

对象的逃逸分析就是指的是:对象的动态指针的范围,如果一个对象的指针是被多个方法和线程进行使用的话,那么该对象就会存在对象逃逸。

如果我们使用逃逸分析原理的话,就是这样的,一个未发生逃逸的对象指针我们不需要让它在堆中进行实例化,我们让他随着方法体直接在栈中开辟一段内存,然后随着方法体的销毁而销毁。

逃逸优化代码:
public void method(){
V v=new User();
//对v的相关的操作
v=null;
}
这样的一段代码是没有发生逃逸对象的。如果jit可以分析除这种代码的话是可以大大的提高运行效率的。

当然在这里我们进行逃逸分析的时候我们还需要进行的是内联的分析,就是把两个用到一个对象的方法体把他们内联起来。

GC针对永久区的回收,通常主要是从两个方面进行分析的,一是GC对永久区常量池的回收,二是永久区对类元数据的回收。
HotSpot虚拟机对于常量池的回收策略是非常的明确的,只要常量池的常量没有被任何地方引用,就可以回收。

要实现Java得缓存有很多种的方式,最简单的无非就是static HashMap,他是基于内存的缓存,但是我们首先要解决的问题是对象的有效期和生命周期。其实java中不是仅仅只有线程池,连接池,常量池,其实还有一个就是对象池。
但是缓存说句实话是一个双刃剑,就是拿hibernate来说,一般情况下是不如jdbc的有效的,因为如果你缓存的数据的准确性太差了的话,是会严重影响其性能的,反之,如果准确率十分高的话,那么hibernate的威力也是无比的巨大的。

在这里我学习到了一个非常重要的知识那就是内联函数,所谓的内联函数就是java也有类似c++中inline函数的机制,即在函数调用时直接将被调用函数的代码拷贝副本过来运行,而不进行普通的压栈当前运行地址,压栈参数,跳转执行然后再返回的过程。在早期版本中,使用final关键字可以建议编译器以内联函数的方式处理这个函数。但是在后来的几个版本中,编译器进行了优化,会自动将适合内联的“小函数”以内联的方式处理,而只有在真正需要禁止override的时候才使用final关键字以避免混乱。

比如 public final dosomething(){
//
}
内联也不是什么时候用都是好的,如果方法体太大的话,现在性能反而还是会下降的,但是现在我们幸运的是java是选择性执行的,如果它觉得程序的结构过大的话,会选择不执行的。

javaAPI的一些优化
1.用clone创建对象
OBJ中有一个方法就是clone(),首先它返回的不是一段内存地址的引用,是一个新的对象。为什么我们建议用它来取代new 对象了? 因为在它克隆的时候会保留原来的一些信息,也就是说这个对象是不会再执行构造方法的。

2.集合的内部避免返回空值

gc中可能采用了不同的算法进行的判断对象的引用是否存在的,但是需要注意的是我们new出来的对象都是强引用类型的,所以jvm宁愿报出oom异常也不会去处理的。在判断中最常用的一种就是引用计数器,当一个新的引用指向某个对象的时候,就是+1,反之就会-1,但是有一个问题,他是不能解决循环孤岛问题的,什么是所谓的循环孤岛问题,就是三个对象进行相互的引用,最后形成了一个孤岛。

正是因为这个问题的存在,所以gc没有采用这种做法。最后采用的是跟踪对象引用的做法,这种做法就是在jvm的内存了找一些存活的对象,依次检测这个对象引用的其他的所有的对象,把这些对象标记为存活,一直到找不到对象为止,最后没有被标记的全部清除。
软引用
软引用是除了强引用外最强的引用类型,当一个持有的

并行的设计模式
Futerue模式,这个模式就像是在网上买东西一样的,你下了订单以后就可以不用管他了,过了几天之后他自己就会到的,在这几天你可以做其他的事情。

原创粉丝点击