《企業實戰分享 · 內存溢出分析》

📢 大家好,我是 【戰神劉玉棟】,有10多年的研發經驗,致力于前后端技術棧的知識沉淀和傳播。 💗
🌻 近期剛轉戰 CSDN,會嚴格把控文章質量,絕不濫竽充數,如需交流,歡迎留言評論。👍

文章目錄

  • 寫在前面的話
    • 書寫背景
    • 知識補充
    • 常見原因
    • 排查方式
  • 使用 JProfiler 排查
    • 具體步驟
  • 使用 VisualVM 排查
    • 監視視圖
    • 線程視圖
    • 抽樣器
    • Visual GC插件
  • 使用Eclipse Memory Analyzer排查
    • 工具介紹
    • Overview組件
    • Top consumers組件
    • Histogram組件
    • Thread Overview組件
    • Domainator Tree組件
    • Leak Suspects組件
    • 常用分析技巧


寫在前面的話

書寫背景

博主所在公司采用的是技術棧為:后端 SpringCloud,前端 Nuxt,部署 K8S。(看過前面文章的應該知道)
由于涉及服務較多,代碼量也隨著需求研發不斷增加,難免出現一些臭魚爛蝦的隱患代碼。
最終導致的是,線上服務的內存溢出問題屢見不鮮,每次排查都要依靠架構等少數人員,現著手整理了一份分析內存溢出問題的流程文檔,方便研發主管人員可以自行排查,而不需要依賴架構部門。
此篇博文將以上述文檔為基礎略為調整,發布到博客,若出現一些未及時調整的話術,希望理解。

知識補充

Tips:這部分純屬知識補充,可以跳過。

關于內存泄漏和內存溢出
一般來說內存異常問題分為內存泄漏和內存溢出。
內存泄漏:對象已經不使用了,但是還占用著內存空間,沒有被釋放。
內存溢出:堆空間不夠用了,通常表現為 OutOfMemoryError,內存泄漏通常會導致內存溢出。
再看一下“內存泄漏”的定義:一個不再被程序使用的對象或變量還在內存中占有存儲空間。
一次內存泄漏似乎不會有大的影響,但內存泄漏堆積后的后果就是內存溢出。
“內存溢出”:指程序申請內存時,沒有足夠的內存供申請者使用,或者說,給了你一塊存儲 int 類型數據的存儲空間,但是你卻存儲 long 類型的數據,那么結果就是內存不夠用,此時就會報錯OOM,即所謂的內存溢出。
二者的關系:內存泄漏的堆積最終會導致內存溢出
**內存泄漏 :**是指你向系統申請分配內存進行使用(new),可是使用完了以后卻不歸還(delete),結果你申請到的那塊內存你自己也不能再訪問(也許你把它的地址給弄丟了),而系統也不能再次將它分配給需要的程序。就相當于你租了個帶鑰匙的柜子,你存完東西之后把柜子鎖上之后,把鑰匙丟了或者沒有將鑰匙還回去,那么結果就是這個柜子將無法供給任何人使用,也無法被垃圾回收器回收,因為找不到他的任何信息。
**內存溢出:就是你要的內存空間超過了系統實際分配給你的空間,此時系統相當于沒法滿足你的需求,就會報內存溢出的錯誤。

內存溢出種類與解決
JVM 管理的內存大致包括三種區域:Heap space(堆區域)、Java Stacks(Java 棧)、Permanent Generation space(永久保存區域)。由此,OOM 簡單的分為堆溢出、棧溢出、永久代溢出(常量池/方法區)。Java 程序的每個線程中都有一個獨立的堆棧。

PS:我們日常開發中,遇到最后的就是堆內存溢出,這里重點介紹這塊,其他兩塊自行了解。

Java 堆內存溢出
Java 堆是線程共有的區域,主要用來存放對象實例,幾乎所有的 Java 對象都在這里分配內存,也是 JVM 內存管理最大的區域。Java堆內存分年輕代和年老代,堆內存溢出一般是年老代溢出。當程序不斷地創建大量對象實例并且沒有被GC回收時,就容易產生內存溢出。當一個對象產生時,主要過程是這樣的:
1、JVM首先在年輕代的Eden區為它分配內存;
2、若分配成功,則結束,否則JVM會觸發一次Young GC,試圖釋放Eden區的不活躍對象;
3、如果釋放后還沒有足夠的內存空間,則將Eden區部分活躍對象轉移到Survivor區,Survivor區長期存活的對象會被轉移到老年代;
4、當老年代空間不夠,會觸發Full GC,對年老代進行完全的垃圾回收;
5、回收后如果Suvivor和老年代仍沒有充足的空間接收從Eden復制過來的對象,使得Eden區無法為新產生的對象分配內存,即溢出。
由此可見,當程序不斷地創建大量對象實例并且沒有被GC回收時,就容易產生內存溢出。如下:

public static void main(String[] args){ArrayList list = new ArrayList();while(true){list.add(new heap());}
}

堆內存溢出很可能伴隨內存泄漏,應首先排查可能泄露的對象,再通過工具檢查 GC roots 引用鏈,從而發現泄露對象是由于何種引用關系使得GC無法回收他們;若不存在內存泄漏,換句話說就是內存中的對象還都需要繼續存活,則可通過修改虛擬機的堆參數將堆內存增大。

補充說明:
堆區域用來存放 Class 的實例(即對象),對象需要存儲的內容主要是非靜態屬性。每次用 new 創建一個對象實例后,對象實例存儲在堆區域中,這部分空間也被 JVM 的垃圾回收機制管理。
java.lang.OutOfMemoryError: Java heap space 此種情況最常見,一般由于內存泄露或者堆的大小設置不當引起。原因是 JVM 創建的對象太多,在進行垃圾回收之間,虛擬機分配的到堆內存空間已經用滿了,與 Heap space 有關。
解決這類問題有兩種思路:
1、對于內存泄露,可以通過內存監控軟件查找程序中的泄露代碼。檢查程序,看是否有死循環或不必要地重復創建大量對象。找到原因后,修改程序和算法。
2、增加 JVM 中 Xms(初始堆大小)和 Xmx(最大堆大小)參數的大小。如:set JAVA_OPTS= -Xms256m -Xmx1024
PS:JVM大小通常運維人員會考慮一個合適的值,研發要注意的就是第一點。

常見原因

首先排除Java程序的JVM配置問題,代碼有哪些常見問題會導致內存溢出:
1、內存中加載的數據量過大,一次從數據庫取出過多數據導致內存溢出;
2、集合類中有對對象的引用,使用完后沒有及時清空,使得 JVM 不能回收;
3、代碼中存在死循環或循環產生過多重復的實體對象;
4、未完待續。。。

排查方式

憑經驗肉眼掃描代碼
針對上述列的常見導致內存溢出的代碼,日常排查代碼可以遵循如下軌跡:
1、檢查對數據庫查詢中,是否有一次獲得全部數據的查詢,一般來說,如果一次取十萬條記錄到內存,就可能引起內存溢出。這個問題比較隱蔽且有潛伏性,在上線前,數據庫中數據較少,不容易出問題,上線后,數據庫中數據多了,一次查詢就有可能引起內存溢出。所以可以使用分頁查詢數據庫;
2、檢查代碼中是否有死循環或遞歸調用導致有大循環重復產生新對象實體;
3、檢查 List、MAP 等集合對象是否有使用完后未清除的問題,集合中存在對對象的引用會導致這些對象不能被 GC 回收;

借助工具定位問題
1、服務啟動的時候,設置其參數,使其支持在發生內存溢出時自動dump內存快照;

PS:也就是通常說的dump文件,這步運維那邊會做好。

2、內存快照文件是后綴為 .hprof 的文件,內存溢出的時候產生,可以從服務器下載到本地;

PS:找運維拿到這個文件,或者從SpringBootAdmin嘗試下載。

3、借助內存溢出排查工具 VisualVM、Jprofiler 等,直接加載hprof文件,按步驟定位問題代碼;

PS:安裝一款你順手的工具,排查一下。

研發人員如何手動操作
1、進入到對應的容器里面去
docker exec -it 容器id /bin/bash
2、ps -ef | grep java 查看java進程id
3、保存堆和棧的現場快照 ,jstack命令用于打印指定Java進程、核心文件或遠程調試服務器的Java線程的Java堆棧跟蹤信息
jstack pid > stack.log
jmap -dump:format=b,file=heap.hprof pid
4、退出容器
5、看情況是否重啟容器
docker restart 容器id
6、將文件從容器導出到宿主機
docker cp 容器id:要導出的文件路徑 宿主機路徑
7、再次進入容器刪掉 相關文件
8、下載文件導本地進行分析并且刪除
9、接下來使用具體工具分析


使用 JProfiler 排查

具體步驟

選擇指定的 dump 文件(后綴是hprof),使用 Jprofiler 加載,第一次可能較慢。

文件范例:D:\cjwmy1013\devlop\zoe-optimus-dia-dc-8157.hprof

image.png
如圖點擊大對象
image.png
image.png
image.png
image.png
image.png

補充說明
若軟件提示內存不夠,可以加大內存,如下:
C:\Users\cjwmy1013.jprofiler11\jprofiler.vmoptions
-Xmx4036m
-Xss2m


使用 VisualVM 排查

VisualVM是jdk自帶的jvm監測工具,主要用來監測cpu、線程和堆內存的使用情況,使用簡單,不需要額外配置,可以支持本地和遠程環境,軟件的位置在jdk的bin目錄下,找到jvisualvm.exe,雙擊打開。
image.png
image.png
image.png

監視視圖

選擇本地的運行的某個進程雙擊,選擇監視tab按鈕就可以查詢到當前進程的cpu、內存、類、線程運行信息
image.png

點擊堆Dump用來生成某一時刻的堆轉儲文件快照(.hprof),并且把堆轉儲信息轉換成堆轉儲標簽內,我們可以看到摘要、類、實例數等信息以及通過 OQL 控制臺執行查詢語句功能,幫助我們分析對象的引用關系、是否有內存泄漏情況的發生。
image.png
堆轉儲的概要包括轉儲的文件大小、路徑等基本信息,運行的系統環境信息,也可以顯示所有的線程信息。
image.png
從類視圖可以獲得各個類的實例數和占用堆大小數,分析出內存空間的使用情況,找出內存的瓶頸,避免內存的過度使用。
image.png
對兩個堆轉儲文件進行比較,通過比較我們能夠分析出兩個時間點哪些對象被大量創建或銷毀。
image.png
image.png
打開實例數視圖需要指定一個類,即在類視圖中雙擊某一個類進入該類的實例數視圖,通過下圖可以看出主要的信息包含該類的實例(對象)總數,單個實例、總實例占堆內存的大小,單個實例在堆內存中的所有字段、值,以及對象與引用對象之間的依賴關系。
image.png

線程視圖

線程視圖顯示當前進程包含的所有線程,類型分為User Thread(用戶線程)、Daemon Thread(守護線程),任何一個守護線程都是整個JVM中所有非守護線程的保姆,Daemon的作用是為其他線程的運行提供便利服務,守護線程最典型的應用就是 GC (垃圾回收器)
image.png
image.png

  • 運行狀態:線程正在運行
  • 休眠狀態:線程在休眠
  • 等待狀態:調用Object.wait的線程,此處要注意,condtion.await并不是此狀態,而是下面的狀態。
  • 駐留狀態:調用了LockSupport.park的線程就是此狀態,常見的有如下:
Lock lock = new ReentrantLock();
lock.lock();
Condition condition = lock.newCondition();
condition.await();
  • 監視狀態:synchrnoiezed獲取鎖被阻塞時的狀態

如果想保存某個時間節點的線程快照信息,就點擊右上角的線程Dump,其實就是執行jstack命令,jstack命令可以生成JVM當前時刻的線程快照。線程快照是當前JVM內每一條線程正在執行的方法堆棧的集合,生成線程快照的主要目的是定位線程出現長時間停頓的原因,如線程間死鎖、死循環、請求外部資源導致的長時間等待等。
image.png

抽樣器

抽樣器可以對該進程的某個時間段的CPU使用情況進行抽樣,即點擊CPU樣例的快照按鈕。
image.png
image.png
image.png
抽樣器同樣可以對內存使用情況進行實時監測,以及保存快照信息,根據內存大小(字節數)降序排序就能快速定位出占用內存較多的類,下圖可以看出是byte[]數組占用了大量內存,如果此時還不能定位到程序哪里的問題,那就通過保存內存的快照,然后分析這個dump。
image.png
根據下圖可以看出byte[]數組實例很少,但是占用的內存很多,繼續向上查找引用它的實例,最后發現是arrayList中引用了byte[],既然問題找到了,后續的解決方法就是在程序中進行定位,優化現有代碼。
image.png
image.png

Visual GC插件

visual gc插件可以清晰的看到堆的使用情況以垃圾收集信息,工具欄選擇插件,可用插件搜索visual gc點擊安裝,
image.png
image.png
安裝完畢后,重啟visualVM,會出現如下圖:
image.png
visual gc分為兩個板塊:
1、visual gc window(即spaces區域)
Metaspace :方法區的內存,如果JDK1.8之前的版本,就是Perm,JDK7和之前的版本都是以永久
Old:老年代
新生代:由Eden、S0、S1組成

每個方框都使用不同的顏色表示,有顏色的區域是占用的空間,空白的是剩余的空間,當程序運行時,會動態的顯示
image.png

2、Graph區域,包含了以時間軸為橫坐標的狀態面板
Compile Time:編譯情況,1407 compoles - 2.644s 表示編譯總數為1407,編譯總耗時為2.644s。
一個脈沖表示一次JIT編譯,脈沖越寬表示編譯時間越長。
Class Loader Time:類加載情況,1709 loaded,0 unloaded - 696.184ms表示已加載的數量為1709,卸載的數量為0,耗時為696.184ms。
GC Time:總的(包含新生代和老年代)gc情況記錄 52 collections,708.580ms Last Cause:Allocation Failure表示一共經歷了52次gc,總共耗時708.580ms。
Eden Space:新生代Eden區內存使用情況
Survivor 0和Survivor 1:新生代的兩個Survivor區內存使用情況
Old Gen:老年代內存使用情況
Metaspace:方法區內存使用情況(最大容量,當前容量)
image.png


使用Eclipse Memory Analyzer排查

工具介紹

Java VisualVM只提供了一些基本的功能,所以我們一般不使用Java VisualVM來分析,而是使用Eclipse Memory Analyzer(MAT)來分析,MAT工具是一款強大的Java堆內存分析工具,特點是免費使用,無需安裝解壓即用,可用于查找內存泄露以及查看內存消耗情況,便于開發或運維人員快速定位內存溢出或內存泄露問題。
需要注意必須安裝jdk1.8環境才能使用
下載地址:https://www.eclipse.org/mat/previousReleases.php
解壓后,雙擊MemoryAnalyzer.exe打開
image.png
界面效果如下:
image.png

這邊寫一個小案例來演示內存不斷增加的場景:

public class Main {public static void main(String[] args) {List<Demo> list = new ArrayList<>();while (true) {list.add(new Demo());}}
}

然后設置啟動參數,讓程序內存溢出時自動生成Dump文件
image.png

-Xmx30m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:\dump

-Xmx30m:最大堆內存為30m -XX:+HeapDumpOnOutOfMemoryError:當JVM發生OOM時,自動生成DUMP文件。 -XX:HeapDumpPath:指定文件路徑,例如:-XX:HeapDumpPath=${目錄}/java_heapdump.hprof。如果不指定文件名,默認為:java_pid.hprof

image.png
當內存溢出的時候自動在指定的目錄下生成了一個hprof文件,然后用Eclipse Memory Analyzer打開這個文件:
image.png

點擊File-》Open Heap Dump,選擇內存溢出生產的.hprof文件,默認選擇Leak Suspects Report泄漏可疑報告
image.png
導入成功之后首先來看這個界面,我們先不著急如何分析問題,先快速了解下面板上各個組件的用法,方便后面的學習。
image.png

Overview組件

OverView功能是導入了dump文件之后,對可能出現的問題做了一個整體性的分析概述,首先呈現在眼前的是以一個形狀圖的方式,快速展現了該文件中dump文件大小,以及類、對象和類加載器的數量,當光標移動到藍色區域時候,會呈現該日志文件的主要線程,類加載器信息。
image.png
![4E3B`I)FS4I4}B3NN%Z_OQ.png
總共使用的內存為24M Thread對象占用了23M,類加載器占用了206kb,其他對象占用了752kb。

Top consumers組件

展示的是占用內存比較多的對象的分布,下面是具體的一些類和占用
![MSN(4598`T$JEKW~H4RT_]5.png](https://img-blog.csdnimg.cn/img_convert/9b754529578285828253081bd16d22f1.png)

Histogram組件

Histogram 可以列出內存中的對象,對象的個數以及大小
Objects:對象的個數
Shallow Heap:對象所占用的本身內存大小(不包含引用對象)
Retained Heap:對象以及它所持有的其它引用(包括直接和間接)所占的總內存大小

當點擊進去之后,為我們呈現出dump文件中,已經創建的主要的對象信息,默認按照對象的個數進行排序,而這個排序,多少也反映出在當前的dump文件中,那些排在前面的數量最多的對象可能是我們分析問題的關鍵入口
image.png
頂部的可以支持對象名稱的模糊匹配,比如搜索Picture,可以快速找到我們需要的對象名稱。
image.png
MAT還提供了分組查看功能,方便快速定位類的信息,默認視圖就是Group by class根據類分組。
image.png
Group by superclass根據父類分組,所有類的父類都是Object,所以會生成樹形結構。
![F`3TDHG8CHI5J3`ZLLPSVM.png
Group by class loader根據類加載器分組
2)3VWXHT23V{~HXP1)N%5Y.png
Group by package根據包目錄分組
image.png
除了分組功能,還支持按照字段排序,右鍵某個對象可以選擇按照類名、對象個數、淺堆數量、深堆數量排序,這也是快速定位到需要查找到的對象的一種方式
![(`X]0DS7UYQ4H163JJJ7HE5.png

這里需要了解淺堆、深堆的概念,因為這兩個參數是分析OOM的一個關鍵點。
淺堆:指的是一個對象所消耗的內存(不包括內部引用的對象大小)
深堆:指的是一個對象直接訪問或者間接訪問到的所有對象的淺堆之和,即對象被回收后,可以釋放的真實空間。
淺堆、深堆總結:對象的深堆個數總是多于淺堆,實際開發過程中,可能因為編碼的習慣不好,導致某些類中,對象的引用鏈條特別長,層級也很深,搞不清楚那些對象是實際在使用的,假如正好有那么一些對象實際上并沒有使用,但是在某些循環中大量創建,尤其是大對象,在這種情況下,很容易造成GC過程的失敗最終引發OOM,所以分析這兩個參數對于快速定位那些數量較多的對象還是很有幫助的。

對象引用鏈:
查看引用當前對象的外部對象可以點擊這個右鍵—》show objects by class-》by incomming references
![KJ(783)WBOKYAUZ4VV({~7.png
查看當前對象引用的外部對象可以點擊這個右鍵—》show objects by class-》by outgoing references
![3[1)Q}RY_M]R}LKQ)KaTeX parse error: Expected 'EOF', got '}' at position 190: …問題的一個很好的點。 ![PP}?EW~X44IIRB7O03)…W.png

Thread Overview組件

Thread Overview展示出當前dump文件中,所有的線程信息,展示出了所有的線程,主線程,以及各個線程中的淺堆和深堆占用的大小,類加載器,是否守護線程等信息。
![9PZQ%HKT$Y2FYPSGMQ84AM.png
以main線程為例,列舉出了里面的成員變量的信息,比如在當前的main線程中,有一個成員變量包含了很多對象,并且淺堆和深堆的大小都很大。
@`_300N$3Q7(VTH4{54)77P.png

Domainator Tree組件

Domainator Tree指的是支配樹的對象圖,支配樹體現了對象實例之間的支配關系,理解支配樹的目的是,在我們分析dump文件時,可以通過支配樹,清楚的知道某個對象引用的對象情況。
N2OV1)MOJLALB0WC@1OD~4B.png
Retained Heap表示這個對象以及它所持有的其它引用(包括直接和間接)所占的總內存,因此從上圖中看,前兩行的Retained Heap是最大的,我們分析內存泄漏時,內存最大的對象也是最應該去懷疑的。

Leak Suspects組件

點擊Leak Suspects查看具體的內存泄露報告,MAT分析工具會根據你導入的dump文件,快速生成一份懷疑報告,將可能出現內存泄露的點展示出來,便于開發或運維人員進行問題定位。
O_B4E(Q0%(FEJ8VPONHD)NY.png
~M8D57C2KA[9]CC.png
在內存泄漏報告中Thread Stack可以清晰的看到內存溢出代碼的位置,對于快速定位程序問題非常方便友好
YW69@($6G}KL5VZPSB1WQ.png

常用分析技巧

第一種:通過Thread Overview線程視圖,按照Retained Heap深堆大小排序,展開線程查看,從調用棧中找到當前服務的代碼。
第二種:通過histogram內存大小直方圖,選擇group by package按照包路徑分組,再按照Retained Heap深堆大小排序,找到當前服務的代碼。
第三種:通過Dominator Tree 支配樹,按照Retained Heap深堆大小排序,然后查看深堆最大的線程在持有哪些大對象,接著在該對象右鍵查看線程詳細堆棧信息。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/40224.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/40224.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/40224.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

用PyQt5打造炫酷界面:深入解析pyqt5-custom-widgets

在PyQt5中&#xff0c;使用自定義小部件可以為應用程序增添更多實用性和時尚感。pyqt5-custom-widgets是一個開源項目&#xff0c;提供了一系列有用且時尚的自定義小部件&#xff0c;如開關按鈕、動畫按鈕等。本文將詳細介紹pyqt5-custom-widgets的安裝和使用方法。 安裝 可以…

權限維持Linux---監控功能Strace后門命令自定義Alias后門

免責聲明:本文僅做技術交流與學習... 目錄 監控功能Strace后門 1、記錄 sshd 明文 監控 篩選查看 2、記錄sshd私鑰 命令自定義Alias后門 1、簡單粗魯實現反彈&#xff1a; 靶機替換命令 攻擊機監聽上線 2.升級(讓命令正常) 將反彈命令進行base64編碼 替換alias命令 …

【Linux】--help,man page , info page

我們知道Linux有很多的命令&#xff0c;那LInux要不要背命令&#xff1f; 答案是背最常用的那些就行了 那有的時候我們想查詢一些命令的詳細用法該怎么辦呢&#xff1f; 這里我給出3種方法 1.--help --help的使用方法很簡單啊 要查詢的命令 --help 我們看個例子 這里我只…

java版企業工程管理系統源碼:全方位的項目管理解決方案

工程管理系統是一款專注于建設工程項目全生命周期管理的軟件。它覆蓋了項目從策劃、設計、施工到竣工的每一個階段&#xff0c;提供全方位的管理功能。系統采用模塊化設計&#xff0c;包括系統管理、系統設置、項目管理、合同管理、預警管理、竣工管理、質量管理、統計報表和工…

李白的酒量之謎

在中國古典文學的璀璨星空中&#xff0c;李白的名字猶如一顆耀眼的星辰&#xff0c;其卓越的文學成就與獨特的人生經歷引得無數后人仰望。特別是“李白斗酒詩百篇”&#xff0c;這句話不僅高度概括了李白的詩歌才華和其對酒精的熱愛&#xff0c;也使得后人對李白的酒量產生了濃…

6月30日功能測試Day10

3.4.4拼團購測試點 功能位置&#xff1a;營銷-----拼團購 后臺優惠促銷列表管理可以添加拼團&#xff0c;查看拼團活動&#xff0c;啟動活動&#xff0c;編輯活動&#xff0c;刪除活動。 可以查看拼團活動中已下單的訂單以狀態 需求分析 功能和添加拼團 商品拼團活動頁 3…

Pytorch中方法對象和屬性,例如size()和shape

文章目錄 方法對象和屬性的基本概念方法對象屬性示例說明總結 常見的方法對象和屬性常見的方法對象常見的屬性總結示例 方法對象和屬性的基本概念 方法對象&#xff08;method object&#xff09;和屬性&#xff08;attribute&#xff09;是面向對象編程中的兩個重要概念。讓我…

python使用pywebview集成vue3和element-plus開發桌面系統框架

隨著web技術越來越成熟&#xff0c;就連QQ的windows客戶端都用web技術來開發&#xff0c;所以在未來&#xff0c;web技術來開發windows桌面軟件也會越來越多&#xff0c;所以在此發展驅動之下&#xff0c;將最近流程的python與web技術相結合&#xff0c;使用vue3和element-plus…

圖像增強 目標檢測 仿射變換 圖像處理 扭曲圖像

1.背景 在目標檢測中&#xff0c;需要進行圖像增強。這里的代碼模擬了旋轉、扭曲圖像的功能&#xff0c;并且在扭曲的時候&#xff0c;能夠同時把標注的結果也進行扭曲。 這里忽略了讀取xml的過程&#xff0c;假設圖像IMG存在對應的標注框&#xff0c;且坐標為左上、右下兩個…

[C++初階]vector的初步理解

一、標準庫中的vector類 1.vector的介紹 1. vector是表示可變大小數組的序列容器 &#xff0c; 和數組一樣&#xff0c;vector可采用的連續存儲空間來存儲元素。也就是意味著可以采用下標對vector的元素進行訪問&#xff0c;和數組一樣高效。但是又不像數組&#xff0c;它的大…

災后恢復與勒索恢復的區別

災難恢復通常側重于物理基礎設施&#xff0c;如硬盤和網絡設備&#xff0c;而勒索軟件恢復則涉及數據完整性和防范網絡威脅。 BackBox 產品管理副總裁 Amar Ramakrishnan表示&#xff0c;在災難中&#xff0c;企業可能面臨硬件受損等問題&#xff0c;但在網絡安全事件中&#…

Java學習高級一

修飾符 static 類變量的應用場景 成員方法的分類 成員變量的執行原理 成員方法的執行原理 Java之 main 方法 類方法的常見應用場景 代碼塊 設計模式 單例設計模式 餓漢式單例設計模式 懶漢式單例設計模式 繼承 權限修飾符

小紅書 達芬奇:生活問答 AI 機器人

小紅書去年 9 月開始內測的生活問答 AI 機器人&#xff1a;達芬奇&#xff0c;現在可以在小紅書 APP 上用了 得益于小紅書平臺的特性&#xff0c;該助手擅長吃、住、寵、喝、學等等各類生活知識&#xff0c;目前還在搞活動&#xff0c;寫評測筆記最高得 666 元

為什么不能在foreach中刪除元素

文章目錄 快速失敗機制&#xff08;fail-fast&#xff09;for-each刪除元素為什么報錯原因分析邏輯分析 如何正確的刪除元素remove 后 breakfor 循環使用 Iterator 總結 快速失敗機制&#xff08;fail-fast&#xff09; In systems design, a fail-fast system is one which i…

合肥高新區建設世界領先科技園區政策(商務部分)申報獎勵補貼和條件材料、時間指南

一、合肥高新區建設世界領先科技園區政策&#xff08;商務部分&#xff09;申報主體 &#xff08;更多政策可以查看小編主頁方式&#xff09; 工商、稅務、統計關系均在合肥高新區&#xff0c;并在高新區持續經營。申請項目在高新區內實施、且符合政策要求的具有獨立法人資格…

網絡基礎:EIGRP

EIGRP&#xff08;Enhanced Interior Gateway Routing Protocol&#xff09;是由思科開發的一種高級距離矢量路由協議&#xff0c;結合了距離矢量和鏈路狀態路由協議的優點&#xff1b;EIGRP具有快速收斂、高效帶寬利用、負載均衡等特點&#xff0c;適用于各種規模的網絡。EIGR…

python sklearn機械學習-數據預處理

&#x1f308;所屬專欄&#xff1a;【機械學習】?作者主頁&#xff1a; Mr.Zwq??個人簡介&#xff1a;一個正在努力學技術的Python領域創作者&#xff0c;擅長爬蟲&#xff0c;逆向&#xff0c;全棧方向&#xff0c;專注基礎和實戰分享&#xff0c;歡迎咨詢&#xff01; 您…

【設計模式】策略模式(定義 | 特點 | Demo入門講解)

文章目錄 定義策略模式的結構 QuickStart | DemoStep1 | 策略接口Step2 | 策略實現Step3 | 上下文服務類Step4 | 客戶端 策略模式的特點優點缺點 定義 策略模式Strategy是一種行為模式&#xff0c;它能定義一系列算法&#xff0c;并將每種算法分別放入到獨立的類中&#xff0c…

書籍表達式得到期望結果的組成種數

題目 給定一個只由0(假)、1(真)、&(邏輯與)、|(邏輯或)和^(異或)五種組成的字符串express&#xff0c;再給定一個布爾值desired。返回express能有多少種組合方式。可以達到desired的結果。 舉例 express“1^0|0|1”,desiredfalse. 只有1^((0|0)|1)和1^(0|(0|1))的組合可…

負載均衡類型和算法解析

假如你正在設計和開發一個分布式服務系統&#xff0c;系統中存在一批能夠獨立運行的服務&#xff0c;而在部署上也采用了集群模式以防止出現單點故障。所謂集群&#xff0c;就是指將多個服務實例集中在一起&#xff0c;對外提供同一業務功能&#xff0c;也就是任意請求都可以由…