本系列专题的目标是希望可以帮助读者们系统和全访问掌握应⽤系统调优的思路与方案以及相关的调优工具的使用,虽然未必会覆盖目前的所有的问题场景,但是还是提供了较为丰富的案例和调优理论,会帮助大家打开思维去⽀撑系统服务体系优化能力。
Java相关的开发人员、系统架构师、数据库DB人员以及运维人员等。
调优手段就是让计算机的硬件或软件在正常地⼯作基础上,非常出色的发挥其应有的性能,并且将所承担的负担降低到最低的技术手段。在Java应用服务体系中有大致可以分为5个维度的调优方向。
如下图所示。
一般从上到下系统优化的层面成本越来越高,而从下到上系统优化层面的成本越来月底,而且难度也适当下降,建议自下而上的去进行调优规划。
采用监控和预防的手段去实现提前发现问题:zabbix、promethus等等
问题排查工具使用机制
定期进行排查和复盘相关的代码问题,加深我们对问题的印象以及防止问题再次发生
制定标准规范,约束问题的发生。
有问题,解决问题。not broken, don't fix.
⼯具旨在帮助我们快速找到应⽤的性能瓶颈。
⽇志分析⼯具⽐较与分析
ELK、GrayLog、SLSLog…
ELK搭建与使⽤
现场演示
调⽤链跟踪⼯具与对⽐
Skywalking、Sleuth + Zipkin、Jaeger…
Skywalking快速发现性能瓶颈
通过复⽤对象,减少对象创建、垃圾回收的开销
维护⼀些很⼤、创建很慢的对象,提升性能
缺点:有学习成本、增加了代码的复杂度
两⼤类对象池:ObjectPool & KeyedObjectPool
实现类如下,其中,最重要、功能最强、使⽤最⼴泛的GenericObjectPool,这个对象池⾮常的强⼤,它⽐较的通⽤,⽽且封装得也⾮常完备。
这种对象池和ObjectPool的区别在于,它是通过key找对象的,从设计上来看和ObjectPool没什么区别。实现类如下,使⽤最⼴的是GenericKeyedObjectPool。
new GenericObjectPool(PooledObjectFactory<T> factory)
new GenericObjectPool(PooledObjectFactory<T> factory, GenericObjectPoolConfig<T> config)
new GenericObjectPool(PooledObjectFactory<T> factory, GenericObjectPoolConfig<T> config, AbandonedConfig abando
nedConfig)
最重要的参数是PooledObjectFactory,⼀般来说,⼯⼚是需要我们⾃⼰根据业务需求去实现的。它是⽤来创建对象的,这其实就是设计模式⾥⾯的⼯⼚模式。
⽬前PooledObjectFactory有两个实现类。
Factory核⼼⽅法:
class MyPooledObjectFactory implements PooledObjectFactory<Model> {
public static final Logger LOGGER = LoggerFactory.getLogger(MyPooledObjectFactory.class);
@Override
public PooledObject<Model> makeObject() throws Exception {
DefaultPooledObject<Model> object = new DefaultPooledObject<>(new Model(1, "S"));
LOGGER.info("makeObject..state = {}", object.getState());
return object;
}
@Override
public void destroyObject(PooledObject p) throws Exception{
LOGGER.info("destroyObject..state = {}", object.getState());
}
@Override
public boolean validateObject(PooledObject p) {
LOGGER.info("validateObject..state = {}", object.getState());
return true;
}
@Override
public void activateObject(PooledObject p) throws Exception{
LOGGER.info("activateObject..state = {}", p.getState());
}
@Override
public void passivateObject(PooledObject p) {
LOGGER.info("passivateObject..state = {}", object.getState());
return true;
}
所有操作面向的都是PooledObject这个参数,makeObject返回的是PooledObject,其他API为什么操作的也是 PooledObject,⽽不是直接操作我们创建的对象呢?
这其实也是commons-pool设计巧妙之处。Pooledobject可以对原始对象进⾏包装,从⽽被对象池管理。⽬前 pooledobject有两个实现类:
本系列专题将针对于Oracle Java HotSpot虚拟机为为开发者们提供不同的Java Heap内存空间的较为深入的分析介绍。对于任何接触的开发者都是非常重要的理论依据。频繁遇到的内存问题,提供生产环境的优化调整。那么适当的实战层级的Java虚拟机的内存空间分析能力是至关重要的。
JVM的堆空间的变化在<18的版本之内,主要有一个分水岭,主要集中在8之前和8之后。
JDK8之前的Heap空间如下图所示:
JDK8之后的Heap空间如下图所示:
主要时针对于方法区的实现机制:永久代 -> 元空间结构模型,接下来我们看看元数据空间在方法区中的分布结构模型。
可以看到JDK8之后,方法去的实现有元空间和一部分堆内存组成。之前主要只有单纯的永久代去实现的。
常量池主要有静态常量池和运行时常量池组成。
类信息
当类加载到内存中后,JVM就会将静态常量池中的内容存放到运⾏时的常量池中;运⾏时常量池⾥⾯存储的主要是编译期间⽣成的字⾯量、符号引⽤等等。如下图对应的字符串常量在字符串常量池中的存储模式。
字符串常量池,也可以理解成运⾏时常量池分出来的⼀部分,类加载到内存的时候,字符串,会存到字符串常量池⾥⾯。
针对于代码的执行和存储在JVM的分布,主要集中在栈空间和堆空间、方法区。它们各个的职能不同,对应的能力也是不同的。我们针对于一段代码块进行分析和介绍
top:显示所有进程运行情况,按M键按照内存大小排序。
top [-] [d] [p] [q] [c] [C] [S] [s] [n]
jps [-q] [-mlvV] [<hostid>]
今天就写到这里,未完待续,等待下一部分的内容。
手机扫一扫
移动阅读更方便
你可能感兴趣的文章