本系列專題的目標是希望可以幫助讀者們系統和全存取掌握應⽤系統調優的思路與方案以及相關的調優工具的使用,雖然未必會覆蓋目前的所有的問題場景,但是還是提供了較為豐富的案例和調優理論,會幫助大家開啟思維去⽀撐系統服務體系優化能力。
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>]
今天就寫到這裡,未完待續,等待下一部分的內容。
本文來自部落格園,作者:洛神灬殤,轉載請註明原文連結:https://www.cnblogs.com/liboware/p/17063422.html,任何足夠先進的科技,都與魔法無異。