檢查硬碟完整性竟導致系統資料毀損,外媒發現 Windows 10 20H2 新問題_網頁設計

※推薦評價好的iphone維修中心

擁有專業的維修技術團隊,同時聘請資深iphone手機維修專家,現場說明手機問題,快速修理,沒修好不收錢

Windows 10 每次更新出現 Bug 已經不是什麼新聞,最近德國媒體 Planet 3D Now 就發現了一個很有問題的 Bug。這個問題一般人未必會用得到,但稍微懂一點電腦的人可能比較容易觸發。根據引發的狀況,無論如何都會出現 BSoD 藍色當機畫面,當機畫面顯示後會進入系統自動修復程序,但根據 Planet 3D Now 的報導,他們發現這個自動修復程序仍然無法解決這個狀況,並發現系統檔案在這個過程中已經毀損。而目前判斷僅有系統版號為 19042.685 的 Windows 10 系統將會出現這個問題,即便虛擬系統環境下,也能重現這個 Bug:

▲Windows 10 這次被自己內建的指令打敗了(圖片來源)

很多熟悉 Windows 系統的玩家多半知道一些終端機指令的實用操作,chkdsk 就是很多玩家熟悉的「檢查硬碟」指令。這個指令搭配一些參數後,可以檢測硬碟完整度,確認硬碟是否有嚴重的損壞或系統資料的毀損。這個指令相當歷史悠久,筆者至少記得在 DOS 系統能使用,而最新的 Windows 10 依然保有這個指令功能。不過這個堪稱骨灰級的指令,卻成為 Windows 10 20H2 的被發現的新問題來源之一。

一個更新竟讓專職檢查硬碟的指令成為當機兇手

根據外媒 Planet 3D Now 給出的結論,這個現象能在一般電腦與虛擬機器中發現,非常容易觸發。考慮到一般人未必會使用這個指令檢查硬碟,因此若非具備一定程度的電腦或 Windows 系統知識,未必會引發這個問題。根據 Planet 3D Now 與其他網友的測試後,發現只要在管理員權限下開啟終端機並輸入 chkdsk c: /f,就會立刻當機,並提示「NTFS FILE SYSTEM 錯誤」,嚴重的甚至會讓系統資料毀損:

▲國外網友很熱心的針對一整個教室的電腦實驗這個 Bug,發現通通無一例外的當機(圖片來源)

目前這個問題已經回報給 Microsoft,相信不久之後這個問題將能獲得解決。不過,一個小小的 chkdsk 指令竟然直接能讓 Windows 10 最新版本系統當機,這對微軟來說的確是個嚴重的形象問題。作為一個電腦編輯, chkdsk 指令雖然不見得天天使用,但至少知道這是個 Windows 內建的功能之一。如果內建功能都能讓系統出現嚴重的當機,那麼 Windows 10 20H2 系統在用戶心中的信賴度將會大幅下降。

網頁設計最專業,超強功能平台可客製化

窩窩以「數位行銷」「品牌經營」「網站與應用程式」「印刷品設計」等四大主軸,為每一位客戶客製建立行銷脈絡及洞燭市場先機。

另外,Planet 3D Now 根據網友們的反覆測試後提出一個新的發現,就是已經過安裝更新,使得系統版本號碼變更為 19042.685 的 Windows 10 20H2 系統肯定會出現這個狀況。但乾淨安裝的 Windows 10 20H2 並不會引發這個問題。從這個發現反推回微軟的更新時間表,可以發現 KB4592438 這個更新正好符合這些特徵。因此若已經安裝此更新的 Windows 10 20H2 系統有可能引發這個 Bug :

▲目前得知更新後成為特定版本的 Windows 10 將出現這個問題(圖片來源)

消息來源:PC Watch

您也許會喜歡:

【推爆】終身$0月租 打電話只要1元/分

立達合法徵信社-讓您安心的選擇

台北網頁設計公司這麼多該如何選擇?

網動是一群專業、熱情、向前行的工作團隊,我們擁有靈活的組織與溝通的能力,能傾聽客戶聲音,激發創意的火花,呈現完美的作品

編程必備基礎之操作系統_網頁設計公司

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

透過選單樣式的調整、圖片的縮放比例、文字的放大及段落的排版對應來給使用者最佳的瀏覽體驗,所以不用擔心有手機版網站兩個後台的問題,而視覺效果也是透過我們前端設計師優秀的空間比例設計,不會因為畫面變大變小而影響到整體視覺的美感。

操作系統概述

  操作系統是管理計算機硬件和軟件資源的計算機程序,管理配置內存、決定資源供需順序、控制輸入輸出設備等。操作系統提供讓用戶和系統交互的操作界面。操作系統的種類是多種多樣的,不局限於計算機,從手機到超級計算機,操作系統可簡單也可複雜,在不同的設備上,操作系統可向用戶呈現多種操作。因為我們不可能直接操作計算機硬件,而且設備種類繁多,需要一個統一的界面,因此有了操作系統,操作系統的簡易性使得更多人能使用計算機。常見的操作系統有:Windows、Linux、MacOS、Android等,總結一句話就是:操作系統是管理硬件、提供用戶交互的軟件系統。

  • 操作系統的基本功能
    • 操作系統統一管理着計算機資源。這些計算機資源包括處理器資源、存儲器資源、IO設備資源和文件資源等。
    • 操作系統實現了對計算機資源的抽象。即用戶無需面向硬件接口編程;IO設備管理軟件,提供獨寫接口;文件管理軟件,提供操作文件的接口。
    • 操作系統提供了用戶和計算機之間的接口。例如圖像窗口形式、命令行形式和系統調用形式等。
  • 操作系統的相關概念
    • 併發性:說到併發就不得不提一下并行性,并行性是指兩個或多個事件可以在同一時刻發生,而併發性是指兩個或多個事件可以在同一個時間間隔發生。
    • 共享性:多個程序可以同時使用主存資源,資源共享根據屬性分為互斥共享和同時訪問兩種形式
      • 互斥共享形式:當資源被程序A佔用時,其他想使用的話就只能等待,只有進程A使用完以後,其他進程才可以使用該資源。
      • 同時訪問形式:某種資源在一段時間內併發地被多個程序訪問,這種“同時”是宏觀的,從宏觀去看該資源可以被同時訪問
    • 虛擬性:虛擬性表現為把一個物理實體轉為若干個邏輯實體,物理實體是真實存在的,邏輯實體是虛擬的,虛擬的技術主要有時分復用技術和空分復用技術。
      • 時分復用技術:資源在時間上進行復用,不同程序進行併發使用,多道程序分時使用計算機的硬件資源,提高資源的利用率
        • 虛擬處理器技術:藉助多道程序設計技術,為每個程序建立進程,多個程序分時復用處理器
        • 虛擬設備技術:物理設備虛擬為多個邏輯設備,每個程序佔用一個邏輯設備,多個程序通過邏輯設備併發訪問
      • 空分復用技術:空分復用技術用來實現虛擬磁盤、虛擬內存等,提高資源利用率,提高編程效率
        • 虛擬磁盤技術:物理磁盤虛擬為邏輯磁盤,例如C、D、E等邏輯盤,使用起來更加安全方便
        • 虛擬內存技術:在邏輯上擴大程序的存儲容量,使用比實際內存更大的容量,大大提升編程效率
    • 異步性:在多道程序環境下,允許多個進程併發執行,進程在使用資源時可能需要等待和放棄,進程的執行並不是一氣呵成的,而是以走走停停的形式推進

進程管理

  為什麼需要進程呢?在沒有配置OS(操作系統)之前,資源屬於當前運行的程序,配置OS之後,引入多道程序設計的概念,可以合理的隔離資源、運行環境、提升資源利用率。進程是系統進行資源分配和調度的基本單位,進程作為程序獨立運行的的載體保障程序正常運行,進程的存在使得操作系統資源的利用率大幅提升。

進程管理之進程實體

主存中得進程形態

  • 標識符:標識符唯一標記一個進程,用戶區別其他進程,如進程id
  • 狀態:標記進程的進程狀態,如:運行態
  • 程序計數器:指向進程即將被執行的下一條指令的地址
  • 內存指針:程序代碼,進程數據相關指針
  • 上下文數據(重要):進程執行時處理存儲器的數據
  • IO狀態信息:被進程IO操作時所佔用的文件列表
  • 記賬信息:使用處理器時間、時鐘數總和等。

  由此可知,主存中的進程形態主要包括進程標識符,處理機狀態,進程調度信息,進程控制信息等。其中進程控制塊(PCB)是用於描述和控制進程運行的通用數據結構,記錄進程當前狀態和控制進程進行運行的全部信息,PCB使得進程成為能夠獨立運行的基本單位。PCB是操作系統進行調度經常會被讀取的信息,而且是常駐內存的,存放在系統專門開闢的PCB區域內。

進程與線程

  之前說過進程是操作系統進行資源分配和調度的基本單位,而線程是操作系統進行運行調度的最小單位,線程包含在進程之中,是進程中實際運行的工作單位,一個進程可以併發多個線程,每個線程執行不同任務。

   進程 線程
資源 資源分配的基本單位 不擁有資源
調度 獨立調度的基本單位 獨立調度最小單位
系統開銷 進程系統開銷大 線程系統開銷小
通信 進程IPC 讀寫同一進程數據通信

  一個進程可以有多個線程,一個進程中的線程共享資源,計算機對進程的調度,實際上是對進程中的線程進行調度

五狀態模型

  • 創建狀態:創建進程時擁有PCB但其它資源尚未就緒的狀態稱為創建狀態,操作系統提供fork函數接口創建進程。
  • 就緒狀態:當進程被分配到除CPU以外的所有必要資源后,只要再獲得CPU的使用權,就可以立即運行。其他資源都轉準備好、只差CPU資源的成為就緒狀態。
    • 在一個系統中處於就緒狀態的進程通常排成一個隊列,稱為就緒隊列。
  • 執行狀態:進程獲得CPU,其程序正在執行稱為執行狀態,再單處理機中,在某個時刻只能有一個進程是處於執行狀態。
  • 阻塞狀態:進程因某種原因如:其他設備未就緒而無法繼續執行,從而放棄CPU的狀態稱為阻塞狀態。
  • 終止狀態:程序執行完成。

進程同步

  為什麼需要進程間的同步呢?先讓我們來看一個經典的問題:生產者-消費者問題
生產者-消費者問題:有一群生產者進程在生產產品,並將這些產品提供給消費者進程進行消費,生產者進程和消費者進程可以併發執行,在兩者之間設置了一個具有n可緩衝區的緩衝池,生產者進程需要將所生產的產品放到一個緩衝區中,消費者進程可以從緩衝區取走產品消費

由上圖我們可以看出,單從生產者程序或消費者程序去看是沒問題的,但兩者併發執行時就可能會出現差錯。如下圖:

這裏的緩衝區就相當於臨界資源。
  再來看一個哲學家進餐問題:
有五個哲學家,他們的生活方式時是交替的進行思考和進餐,哲學家們共同使用一張圓桌子,分別坐在周圍的五張椅子上,在圓桌上有五個碗和五支筷子。平時哲學家們只進行思考,飢餓時則試圖取靠近他們的左、右兩隻筷子,只有兩支筷子都被他拿到的時候才能進餐,進餐完畢后,放下左右筷子繼續思考。

  出現上圖中的問題是什麼呢?其根源問題是:彼此之間沒有相互通信,如果“生產者通知消費者我已經完成了一件生產”,“哲學家向旁邊哲學家說我要進餐了”,就不會出現上圖中的問題了,也就是需要進程間的同步。

  什麼是進程同步呢?當對競爭資源在多個進程間進行使用次序的協調,使得併發執行的多個進程之間可以有效使用資源和相互合作。這裏的競爭資源也就是上圖中的臨界資源,什麼是臨界資源?臨界資源指的是一些雖作為共享資源,卻又無法同時被多個線程共同訪問的共享資源。當有進程在使用臨界資源時,其他進程必須依據操作系統的同步機制,等待佔用進程釋放該共享資源,才可以重新競爭使用共享資源。
進程同步的原則:

  • 空閑讓進:資源五佔用,允許使用
  • 忙則等待:資源有佔用,請求進程等待
  • 有限等待:保證有限等待時間能夠使用資源
  • 讓權等待:等待時,進程需要讓出CPU

  進程間同步的常用方法:如消息隊列,共享存儲,信號量。當多個線程併發使用進程資源時,進程內的多線程也需要,因為進程中的資源時進程中線程的共享資源。線程同步的方法有:互斥量、讀寫鎖、自旋鎖、條件變量等,這些方法是如何保證線程同步的呢?

  • 互斥量:由於多個線程的指令交叉執行,而互斥量可以保證先後執行,即保證原子性。什麼是原子性呢?原子性是指一系列操作不可被中斷的特性, 這一系列操作要麼全部執行完成,要麼全部沒有執行,不存在部分執行部分未執行的情況
    • 互斥量是最簡單的線程同步方法
    • 互斥量(互斥鎖),處於兩態之一的變量:解鎖和加鎖
    • 兩個狀態可以保證資源的串行
  • 自旋鎖:自旋鎖也是一種多線程同步的變量,使用自旋鎖的線程會反覆檢查鎖變量是否可用,自旋鎖不會讓出CPU,是一種忙等待狀態,即死循環等待鎖被釋放。
    • 自旋鎖避免了進程或線程上下文切換的開銷
    • 操作系統內部很多地方都是使用的自旋鎖
    • 自旋鎖不適合在單核CPU中使用
  • 讀寫鎖:這種鎖適用於臨界資源多讀少寫,讀取的時候並不會改變臨界資源的值。
    • 讀寫鎖是一種特殊的自旋鎖
    • 允許多個讀者同時訪問資源以提高讀的性能
    • 對寫的操作則是互斥的
  • 條件變量
    • 條件變量是一種相對複雜的同步方法
    • 條件變量允許線程睡眠,直到滿足某種條件
    • 當滿足條件時,可以向該線程發送信號,通知喚醒
同步方法 描述
互斥鎖 最簡單的一種線程同步方法,會阻塞線程
自旋鎖 避免切換的一種線程同步方法,屬於“忙等待”
讀寫鎖 為“讀多寫少”的資源設計的線程同步方法,可以顯著提高性能
條件變量 相對複雜的一種線程同步方法,有更靈活的使用場景

進程同步之共享內存
  在某種程度上,多進程是是共同使用物理內存的,由於操作系統的進程管理,進程間的內存空間是獨立的,進程默認是不能訪問進程空間之外的內存空間的

共享內存就可以打破這個限制,因為有這個共享內存,不同進程就可以通過頁表映射到同一個共享內存去,這個共享內存既可以被進程1使用,也可以被進程2使用。

  共享存儲允許不相關的進程訪問同一片物理內存,共享內存是兩個進程之間共享和傳遞數據的最快方式,共享內存未提供同步機制,需要藉助其他機制訪問。通過共享內存同步的過程就是:申請共享內存->連接到進程空間->使用共享內存->脫離進程空間並且刪除。共享內存是高性能後台開發中最常用的同步方式。
進程同步之Unix域套接字
  域套接字是一種高級的進程間通信的方法,Unix域套接字可以用於同一台機器進程間通信。其運行過程是創建套接字->綁定(bind)套接字->監聽(listen)套接字->接收&處理信息。域套接字提供了簡單可靠的進程通信同步服務,只能在單機使用,不能跨機器使用。

Linux的進程管理

Linux進程的相關概念:

進程類型:

  1. 前台進程:前台進程就是具有終端,可以和用戶交互的進程
  2. 後台進程:
    • 與前台進程相對,沒有佔用終端的就是後台進程
    • 後台進程基本上b不和用戶交互,優先級比前台進程低
    • 將需要執行的命令以“&”符號結束
  3. 守護進程(daemon):特殊的後台進程
    • 很多守護進程在系統引導的時候啟動,一直運行到系統關閉
    • Linux系統有很多典型的守護進程。例如:crond,sshd,httpd,mysqld等,進程名字以“d”結尾的一般都是守護進程。
      進程標記:
  • 進程ID
    • 進程ID是進程的唯一標記,每個進程擁有不同的ID
    • 進程ID表現為一個非負整數,最大值由操作系統限定
    • 操作系統提供fork()函數接口創建進程。例如進程A調用fork接口創建了進程B,進程B調用fork接口創建了進程C,那此時進程A和進程B就存在父子進程關係,進程A是父進程,進程B是子進程。進程的父子關係可以通過pstree命令查看。

ID為0的進程是idle進程,是系統創建的第一個進程,ID為1的進程init進程,是0號進程的子進程,完成系統初始化,Init進程是所有用戶進程的祖先進程。

  • 進程的狀態標記

Linux中進程的狀態如下:

狀態符號 狀態說明
R (TASK_RUNNING),進程正處於運行狀態
S (TASK_INTERRUPTIBLE),進程正處於睡眠狀態
D (TASK_UNINTERRUPTIBLE),進程正處於IO等待的睡眠狀態
T (TASK_STOPPED),進程正處於暫停狀態
Z (TASK_DEAD or EXIT_ZOMBIE),進程正處於退出狀態,或殭屍進程

操作Linux進程的相關命令

  • ps命令:ps命令常用於显示當前進程的狀態,ps命令常配合aux參數或ef參數和grep命令檢索特定進程
  • top命令
  • kill命令:kill命令發送指定信號給進程,kill-l可以查看操作系統所支持的系統

作業管理

作業管理之進程調度

  進程調度是指計算機通過決策,決定哪個就緒進程可以獲得CPU使用權。通俗來說就是保留舊進程的運行信息,請出舊進程(收拾包袱),選擇新進程,準備運行環境並分配CPU(新駐進)。那麼是如何進行進程的調度的呢?

  • 就緒隊列的排隊機制:將就緒進程按照一定的方式排成隊列,以便調度程序可以最快找到就緒進程。
  • 選擇運行進程的委派機制:調度程序以一定的策略選擇就緒進程,將CPU資源分配給它
  • 新老進程的上下文切換機制:保存當前進程的上下文信息,裝入被委派執行進程的運行上下文

  進程的調度方式分為搶佔式調度和非搶佔式調度。非搶佔式調度是指處理器一旦分配給某個進程,就讓該進程一直使用下去,調度程序不以任何原因搶佔正在被使用的處理器,直到進程完成工作,或因為IO阻塞才會讓出處理器;搶佔式調度是指允許調度程序以一定的策略,暫停當前運行的進程,保存好進程的上下文信息,分配處理器給新進程。

   搶佔式調度 非搶佔式調度
系統開銷 頻繁切換,開銷大 切換次數少,開銷小
公平性 相對公平 不公平
應用 通用系統 專用系統

進程調度算法

  • 先來先服務調度算法
  • 短進程優先調度算法:調度程序優先選擇就緒隊列中估計運行時間最短的進程;短進程優先調度算法不利於長作業進程的運行
  • 高優先權優先調度算法:進程附帶優先權,調度程序優先選擇權最高的進程,高優先權優先調度算法使得 緊迫的任務可以處理
  • 時間片輪轉調度算法:按先來先服務的原則排列就緒進程,每次從隊列頭部取出待執行進程,分配一個時間片執行;是相對公平的調度算法,但不能保證及時響應用戶

作業管理之死鎖

  死鎖是指兩個或兩個以上的進程在執行過程中,由於競爭資源或者由於彼此通信而造成的一種阻塞現象,若無外力作用,他們都將無法推進下去。此時稱系統處於死鎖狀態或系統產生了死鎖,這些永遠在互相等待的進程稱為死鎖進程。
死鎖的產生

  • 競爭資源:共享資源數量不滿足各個進程需求,各個進程 之間發生資源競爭導致死鎖,
  • 進程調度順序不當
    死鎖的四個必要條件:
  • 互斥條件:進程對資源的使用是排他性的使用,某資源只能由一個進程使用,其他進程需要使用只能等待
  • 請求保持條件:進程至少保持一個資源,又提出新的資源請求,新資源被佔用,請求被阻塞,被阻塞的進程不釋放自己保持的資源
  • 不可剝奪條件:進程獲得的資源在未完成使用前不能被剝奪,獲得的資源只能由進程自生釋放
  • 環路等待條件:發生死鎖時,必然存在進程-資源環形鏈
    死鎖的處理
  • 預防死鎖的方法
    • 摒棄請求保持條件:系統規定進程運行之前,一次性申請所有需要的資源,進程在運行期間不會提出資源的請求,從而摒棄請求保持條件
    • 摒棄步課剝奪條件:當進程請求一個新的資源得不到滿足時,必須釋放佔有的資源,當進程運行時佔有的資源可以被釋放,意味着可以被剝奪
    • 摒棄環路等待條件:可用資源線性排序,申請必須按照需要遞增申請,線性申請不在形成環路,從而摒棄了環路等待條件
  • 銀行家算法:銀行家算法是一個可操作得著名得避免死鎖得方法,以銀行借貸系統分配策略為基礎的算法。
    • 客戶申請的貸款是有限的,每次申請須聲明最大資金量
    • 銀行家在能夠滿足貸款時,都應該給用戶貸款
    • 客戶在使用貸款后,能夠及時歸還貸款。

根據還需要分配的資源表,對比可分配資源表,先給能夠滿足貸款的用戶,給用戶貸款,即圖中的P2,P2使用完資源后,需要及時歸還資源

存儲管理

  早期計算機編程並不需要過多的存儲管理,隨着計算機和程序越來越複雜,存儲管理成為必要。

  • 確保計算機有足夠的內存處理處理數據
  • 確保程序可以從可用內存中,獲取一部分內存使用
  • 確保程序可以歸還使用后的內存,已供其他程序使用

存儲管理之內存分配與回收

內存分配的過程

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

節能減碳愛地球是景泰電動車的理念,是創立景泰電動車行的初衷,滿意態度更是服務客戶的最高品質,我們的成長來自於你的推薦。

  • 單一連續分配:單一連續分配是最簡單的內存分配方式,只能在單一用戶、單進程的操作系統中使用
  • 固定分區分配:固定分區分配是支持多道程序的最簡單的存儲分配方式,內存空間被劃分成若干個固定大小的區域,每個分區只提供給一個用戶使用,互不干擾
  • 動態分區分配:根據進程實際需要,動態分配內存空間,相關數據結構、分配算法如下:
    • 動態分區空閑表數據結構:對空閑區進行標記,0表示空閑區,1表示已被使用
    • 動態分區空間鏈數據結構
    • 首次適應算法(FF算法):分配內存時從開始,順序查找適合內存區,若沒有合適的空閑區,則該次分配失敗;每次從頭部開始,使得頭部地址不斷被劃分
    • 最佳適應算法(BF算法):最佳適應算法要求空閑鏈表按照容量大小排序,遍歷空閑鏈表找到最佳合適的空閑區
    • 快速適應算法(QF算法):快速適應算法要求有多個空閑區鏈表,每個空閑區鏈表存儲一種容量的空閑區

內存回收的過程

  情況一:不需要新建空閑鏈表節點,只需要把空閑區1的容量增大為空閑區即可;情況二:將回收區與空閑區合併,新的空閑區使用回收區的地址;情況三:將空閑區1、空閑區2和回收區合併,新的空閑區使用空閑區1的地址;情況四:為回收區創建新的空閑節點,插入到相應的空閑區鏈表中去。

存儲管理之段頁式存儲管理

  由於每個進程都有自己獨立的進程空間,那操作系統是如何管理進程的空間呢?

  • 頁式存儲管理:
    • 將進程邏輯空間等分為若干大小的頁面
    • 相應的把物理內存空間分成與頁面大小的物理塊
    • 以頁面為單位把進程空間裝進物理內存中分散的物理塊

      頁表:頁表記錄了進程邏輯空間與物理空間的映射

現代計算機系統中,可以支持非常大的邏輯地址空間(\(2^{32}\)~\(2^{64}\)),這樣,頁表就變得非常大,要佔用非常大的內存空間,如具有32位邏輯地址空間的分頁系統,規定頁面大小為4KB,則在每個進程頁表中的頁表項可達1M(32位系統進程的尋址空間為4G,4G/4KB=1M)個,如果每個頁表項佔用1Byte,故每個進程僅僅頁表就要佔用1M的內存空間。

  • 段式存儲管理
    • 將進程邏輯空間劃分成若干段(非等分)
    • 段的長度由連續邏輯的長度決定
    • 主函數MAIN,子程序段X,系函數Y等

  段式存儲和頁式存儲都離散地管理了進程的邏輯空間。頁是物理單位,段是邏輯單位,分頁是為了合理利用空間,分段是為了滿足客戶需求;頁大小由硬件空間,段長度可動態變化;頁表信息是一維的,段表信息是二維的。

  • 段頁式存儲管理:由於分頁可以有效提高內存利用率(雖然說存在內存碎片),分段可以滿足用戶需求,我們可以將兩者結合,形成段頁式存儲管理。
    • 先將邏輯空間按段式管理分成若干段
    • 再把段內空間按頁式管理等分成若干頁

存儲管理之虛擬內存

  思考:一個遊戲十幾個G,物理內存只有4G,那這個遊戲是如何運行起來的呢?

  有些進程實際需要的內存很大,超過物理內存的容量,多道程序設計,使得每個進程可用物理內存更加稀缺,不可能無限增加物理內存,物理內存總有不夠的時候,這個時候就需要虛擬內存了。虛擬內存是操作系統內存管理的關鍵技術,使得多道程序運行和大程序運行成為現實,把程序使用內存劃分,將部分暫時不使用的內存放置在輔存。

程序的局部性原理:局部原理是指CPU訪問存儲器時,無論是存取指令還是存取數據,所訪問的存儲單元都趨於集中在一個較小的連續區域中。

  • 程序運行時,無需全部裝入內存,裝載部分即可
  • 如果訪問頁不在內存,則發出缺頁中斷,發起頁面置換
  • 從用戶層面看,程序擁有很大的空間,即是虛擬內存
  • 虛擬內存實際是對物理內存的補充,速度接近於內存,成本接近於輔存

虛擬內存的置換算法:和我在《計算機組成原理》這篇博客中的高速緩存的置換策略差不多,這裏就不詳細介紹了。

  • 先進先出算法(FIFO)
  • 最不經常使用算法(LFU)
  • 最近最少使用算法(LRU)

高速緩存的替換策略發生在Cache-主存層次,只要是為了解決速度問題;虛擬內存的替換策略發生在主存-輔存層次,主要是為了解決容量問題。

Linux的存儲管理

Buddy內存管理算法

  • Buddy算法是經典的內存管理算法
  • 算法基於計算機處理二進制的優勢具有極高的效率
  • 算法主要是為了解決內存外碎片的問題

頁內碎片:內部碎片是已經被分配出去(能明確指出屬於哪個進程)的內存空間大於請求所需的內存空間,不能被利用的內存空間就是內部碎片。
頁外碎片:外部碎片是指還沒有被分配出去(不屬於任何進程),但是由於大小而無法被分配給申請內存空間的新進程的內存空閑塊。
Buddy是夥伴的意思,這裏的”夥伴“指的是內存的”夥伴“,一片連續內存的”夥伴“是相鄰的另一片大小一樣的連續內存
Buddy內存管理算法執行過程:創建一系列空閑塊鏈表,每一種都是2的冪 –> 現在需要分配100kb內存 –> 回收剛才分配的內存

Linux的交換空間

  交換空間(Swap)是磁盤的一個分區,Linux物理內存滿時,會把一些內存交換至Swap空間,Swap空間是初始化系統時配置的。

冷啟動內存依賴:對於一些大型的應用程序,在啟動的過程中需要使用大量的內存,但是這些內存很大一部分只是在啟動的時候使用一下,在運行的時候很少使用到這部分內存,因此有了這個交換空間,系統就可以將這個部分不怎麼使用的內存數據保存在SWAP空間中,從而釋放跟多的物理內存,提供給這個系統使用。

系統睡眠依賴: 當Linux系統需要睡眠的時候,它就會把系統中的所有數據都保存在swap空間內,等下次這個系統需要啟動的時候,才把這些數據重新加載到內存中裏面,這樣就可以加快系統的啟動速度。

大進程空間依賴:有些進程確實需要使用大量的內存空間,但是物理內存不夠使用,因此需要把這些進程需要使用的內存暫時保存到交換空間中,使得這個大的進程也可以運行起來

Swap空間和虛擬內存的對比:

Swap空間 虛擬內存
存儲位置 Swap空間存在於磁盤 虛擬內存存在於磁盤
置換層次 Swap空間與主存發生置換 虛擬內存與主存發生置換
所屬概念 Swap空間是操作系統概念 虛擬內存是進程概念
解決的問題 Swap空間解決系統物理內存不足問題 虛擬內存解決進程物理內存不足的問題

操作系統的文件管理

文件的邏輯結構

  • 邏輯結構的文件類型
    • 有結構文件:例如文本文件、文檔、媒體文件等
      • 文件內容由定長記錄和可變記錄組成
      • 定長記錄存儲文件格式、文件描述等結構化數據項
      • 可變長記錄存儲文件具體內容等
    • 無結構文件:例如二進制文件、鏈接庫等
      • 也稱為流式文件,如exe文件、dll文件、so文件等
      • 文件內容長度以字節為單位
  • 順序文件
    • 順序文件是指按順序存放在存儲介質中的文件
    • 磁帶的存儲特性使得磁帶文件只能存儲順序文件
    • 順序文件是所有邏輯文件當中存儲效率最高的
  • 索引文件
    • 可變長文件不適合使用順序文件格式存儲
    • 索引文件是為解決可變長文件存儲而發明的一種文件格式
    • 索引文件需要配合索引表完成存儲的操作

輔存的存儲空間分配

  • 輔存的分配方式
    • 連續分配:順序讀取文件內容非常容易,速度很快,對存儲要求高,要求滿足容量的連續存儲空間
    • 鏈接分配:鏈接分配可以將文件存儲在離散的盤塊中,需要額外的存儲空間存儲文件的盤塊鏈接順序
      • 隱式鏈接:隱式分配的下一個鏈接指向存儲在當前盤塊內,隱式分配適合順序訪問,隨機訪問效率低,可靠性差,任何一個鏈接出問題都會影響整個文件
      • 显示鏈接:不支持高效的直接存儲(FAT記錄項多),檢索時FAT表佔用較大的存儲空間(需要將整個FAT表加載到內存)
    • 索引分配:把文件的所有盤塊集中存儲(索引),讀取某個文件時,將文件索引讀取進內存即可

      每個文件擁有一個索引塊,記錄所有盤塊信息,索引分配方式支持直接訪問盤塊,文件較大時,索引分配方式具有明顯優勢

  • 存儲空間管理
    • 空閑表:空閑盤區的分配與內存的分配相似,首次適應算法、循環適應算法等,回收過程也與內存回收類似
    • 空閑鏈表:空閑鏈表法把所有空閑盤區組成一個空閑鏈表,每個鏈表節點存儲空閑盤塊和空閑的數目
    • 位示圖:位示圖維護成本很低,可以非常容易找到空閑盤塊,位示圖使用0/1比特位,佔用空間小

目錄管理

  任何文件或目錄都只有唯一路徑。文件常見的描述信息有:文件標識符、文件類型、文件權限、文件物理地址、文件長度、文件連接計數、文件存取時間、索引節點編號、文件狀態、訪問計數、鏈接指針等。

Linux文件基本操作

Linux目錄

目錄 描述
/bin 存放二進制可執行文件(ls,cat,mkdir),常用的命令都在該目錄下
/etc 存放系統管理和配置文件
/home 存放所有用戶文件的根目錄,使用戶目錄的基點,比如用戶user的主目錄就是/home/user
/usr 用戶存放系統應用程序,比較重要的目錄/usr/local本地系統管理員軟件安裝目錄
/opt 額外安裝的可選應用程序包所放置的位置
/proc 虛擬文件系統目錄,是系統內存的映射,可直接訪問這個目錄來獲取系統信息
/root 系統管理員的主目錄
/sbin 存放二進制可執行文件,只有root才能當問
/dev 用於存放設備文件
/mnt 系統管理員安裝臨時文件系統的安裝點,系統提供這個目錄是讓用戶臨時掛載其他的文件系統
/boot 存放用於系統引導時使用的各種文件
/lib 存放跟文件系統種的程序運行所需要的共享庫及內核模塊
/var 用於存放運行時需要改變數據得文件

Linux文件常用操作

  創建文件:touch file 修改文件:vim file 查看文件:cat file 刪除文件:rm file 創建文件夾:mkdir dir 刪除文件夾:rm dir/ 該方式會提示,不能刪除文件夾 遞歸刪除文件夾:rm -r dir/ 進入文件后,通過ls -al 命令可以查看該文件的文件類型,即第一個字符

Linux文件類型

  Linux的文件類型有:套接字(s)、普通文件(-)、目錄文件(d)、符號鏈接(b、c)、設備文件、FIFO(p)

Linux文件系統

文件系統概覽

  • FAT(File Allocation Table):例如FAT16、FAT32等,微軟Dos/Windows使用的文件系統,使用一張表保存盤塊的消息
  • NTFS(New Technology File System):WindowsNT環境文件系統,NTFS對FAT進行了改進,取代了舊的文件系統
  • EXT(Extended file System):擴展文件系統,這個是Linux的文件系統,EXT2/3/4數字錶示第幾代。
    • Boot Selector:啟動扇區,安裝開機管理程序
    • Block Group:塊組,存儲數據的實際位置

EXT文件系統

  Inode Table是存放文件Inode的地方,每一個文件(目錄)都有一個Inode,是每一個文件(目錄)的索引節點。文件名不是存放在Inode節點上的,而是存放在目錄的Inode節點上,列出目錄文件的時候無需加載文件的Inode。Inode bitmap即Inode的位示圖,記錄已分配的Inode和未分配的Inode。Data block是存放文件內容的地方,每個block都有唯一的編號,文件的block記錄在文件的Inode上。Block bitmap功能與Inode bitmap類似,記錄Data block的使用情況。superblock是記錄整個文件系統相關信息的地方,包括block和Inode的使用情況,以及時間、控制信息等。

  命令 df -T:查看該系統所掛載的磁盤信息,查看文件系統的Inode信息:dumpe2fs 指定某個一設備,如 dumpe2fs /dev/sda2,使用超級管理員權限查看:sudo dumpe2fs /dev/sda2,查看文件的具體信息:stat dumpe2fs.log,文件重命名: mv dumpe2fs.log dumpe2fs.bak.log。Inode編號才是文件的唯一標記,文件名不是文件的唯一標記。

操作系統的設備管理

廣義的IO設備

  對CPU而言,凡是對CPU進行數據輸入的都是輸入設備;對CPU而言,凡是CPU進行數據輸出的都是輸出設備

  • 按使用特性分類
    • 存儲設備:U盤、內存、磁盤等
    • 交互IO設備:鍵盤、显示器、鼠標等
  • 按信息交換的單位分類
    • 塊設備:磁盤、SD卡
    • 字符設備:打印機、Shell終端
  • 按設備的共享屬性分類:獨佔設備、共享設備、虛擬設備
  • 按傳輸速率分類:底速設備、中速設備、高速設備

IO設備的緩衝區

  由於CPU與IO設備的速率不匹配,所以需要IO設備緩衝區,這樣可以減少CPU處理IO請求的頻率,提高CPU與IO設備之間的并行性。專用緩衝區只適用於特定的IO進程,當這樣的IO進程比較多時,對內存的消耗也很大,操作系統劃出可供多個進程使用的公共緩衝區,稱之為緩衝池。

SPOOLing技術

  SPOOLing技術是關於慢速字符設備如何與計算機主機交換信息的一種技術,利用高速共享設備將低速的獨享設備模擬為高速的共享設備。邏輯上,系統為每一個用戶都分配了一台獨立的高速共享設備。SPOOling技術把同步調用低速設備改為異步調用。SPOOLing技術在輸入、輸出之間增加了排隊轉儲環節(輸入井、輸出井),SPOOLing技術負責輸入(出)井與低速設備之間的調度,邏輯上,進程直接與高速設備交互,減少了進程的等待時間。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

搬家費用:依消費者運送距離、搬運樓層、有無電梯、步行距離、特殊地形、超重物品等計價因素後,評估每車次單

Counterpoint公布2020第三季報告,聯發科逆襲成為最大手機晶片供應商_網頁設計公司

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

節能減碳愛地球是景泰電動車的理念,是創立景泰電動車行的初衷,滿意態度更是服務客戶的最高品質,我們的成長來自於你的推薦。

2020 年因為疫情的持續擴散,對各種產業來說都是個凜冬,然而還是有些企業在冷清的時局中創下不錯的成績,聯發科就是其中的一員。根據市場研究機構 Counterpoint 最新公布的 2020 年第三季報告中,更是顯示因為中階手機的蓬勃發展與在關鍵地區的市場持續增長,幫助聯發科逆襲高通,於第三季中登上最大智慧手機晶片供應商的寶座。

Counterpoint公布2020第三季報告,聯發科逆襲高通成為最大手機晶片供應商

在 2020 年第三季中,聯發科在 100 至 200 美元價位的手機間強勁增長,以及於至中國、印度等地區的增長,讓聯發科以 31% 的市場佔比成為最大的智慧手機晶片組供應商。於此同時,2020 年第三季最大的 5G 晶片供應商由高通穩坐,在全球市場的 5G 手機中擁有 39% 的佔比。5G 手機的需求量在 2020 年第三季翻了一倍,光是在這一季裡面售出的智慧型手機中有 17% 是 5G 手機,隨著 Apple 推出其 5G 產品線後,更是加速了 5G 手機的銷售。2020 年第四季度發貨的所有智慧型手機中,預計會有三分之一支援 5G,所以高通仍有可能於 2020 年第四季重新奪回榜首位置。

在對聯發科市場佔比增長的部分,分析師表示聯發科在 2020 年第三季市場佔比猛烈增長主要原因有三。首先是中階智慧型手機與新興市場的強勢表現相當亮眼,美國隊華為的禁令也使得最終讓 Samsung、小米、榮耀等 OEM 廠勝出。與去年同期相比,聯發科晶片在小米手機的佔比增長 3 倍以上,而聯發科也利用美國禁令的時機彌補了晶片需求缺口,使得由台積電製造、經濟實惠的聯發科晶片迅速成為許多 OEM 廠商填補空白的第一選擇。

從另一個方面來看,高通在 2020 年第三季裡面於高階領域與一年前相比也取得了強勁的市佔增長,這再次得益於 HiSilicon 的供應問題,然而高通在中階市場面臨著聯發科的競爭,顯然這一仗打得比較吃力。透過激進的訂價策略和主流 5G 晶片產品的推出,兩者之間激烈的兢爭在 2021 年還會繼續。

高通和聯發科都重新對各自的產品線重新洗牌,消費者對最新科技的關注在其中發揮了關鍵作用。去年,聯發科推出了一款以遊戲為主的曦力 G 系列晶片,而天璣系列晶片則將 5G 導向更經濟實惠的路線,全球最便宜的 5G 行動裝置 realme V3 就是由聯發科提供支援。分析師表示,晶片供應商的當務之急是將 5G 帶給大眾,從而釋放如雲端遊戲等消費者 5G 使用的潛力,進而提升對更高時脈 GPU 和更強大的處理器需求。

南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

搬家費用:依消費者運送距離、搬運樓層、有無電梯、步行距離、特殊地形、超重物品等計價因素後,評估每車次單

◎資料來源:Counterpoint

您也許會喜歡:

【推爆】終身$0月租 打電話只要1元/分

立達合法徵信社-讓您安心的選擇

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

透過選單樣式的調整、圖片的縮放比例、文字的放大及段落的排版對應來給使用者最佳的瀏覽體驗,所以不用擔心有手機版網站兩個後台的問題,而視覺效果也是透過我們前端設計師優秀的空間比例設計,不會因為畫面變大變小而影響到整體視覺的美感。

臘月_網頁設計公司

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

透過選單樣式的調整、圖片的縮放比例、文字的放大及段落的排版對應來給使用者最佳的瀏覽體驗,所以不用擔心有手機版網站兩個後台的問題,而視覺效果也是透過我們前端設計師優秀的空間比例設計,不會因為畫面變大變小而影響到整體視覺的美感。

臘月一到,天地就顯得空曠起來。雪要是在晚上降臨,規模又不小,就能給人們十足的驚喜。夜裡,那幾聲竹折的聲音,已經把夢的暖意加重了。清晨,打開門,偌大的雪光馬上席捲了你,你的思緒飛揚在群山和原野。無論小雪和大雪,臘月的雪總是喜氣的,所以都叫做“瑞雪”,表達着一種憧憬的歡喜。臘月是農曆的最後一個月,既然是“最後”,就必須要有一個了結,如此,一場紛紛揚揚的大雪,不妨看作是一場對季節盛大的祭掃,掃掉塵垢,掃掉陰霾,掃掉煩憂。

其實,從正月開始,時令都是搖擺和躁動的,那些紅紅綠綠,那些喧鬧奔放,你來我往地熱鬧着。而時間抵達臘月,抵達大雪以後,就是抵達了冷峻和深寒,茫茫原野,除了點染着幾抹幾點樹木、斷崖、牆壁、瘦瘦的水,皆是雪的天地。

在臘月,花信風也吹着。瑞香、蘭草、水仙、山茶……這些花骨朵,要麼雅緻,要麼野性,叫臘月有了些許的浪漫。尤其是梅花,因為文人騷客的渲染和寄託,似乎把臘月的風姿都佔盡了,其實,對於尋常百姓家,倒是特別惦記着臘梅的。臘梅比梅花來得早些,屬於灌木一類。在牆角,在籬邊,在園子那頭,不管寒冷天氣的意見如何,臘梅自顧自就動了靈氣,於光溜溜的枝頭笑出聲來。開始是一絲絲的淺笑,後來一棵樹、兩棵樹都笑開了去。臘梅的出身在低處、在偏僻、在旮旯,她無所謂,那些花瓣即使被雪裹着、被冰割着,也總是金燦燦地呼吸着,幽幽的清香不動聲色、不卑不亢、不絕如縷。臘梅,不想風光,也不甘沉淪寂寞,真是一個頑強的精靈。“疏林凍水熬寒月,唯見一株在喚春”“枝橫碧玉天然瘦,戀破黃金分外香”,這樣的詩句寫臘梅,也算貼切,但又覺得有點矯情了:臘梅的品性,本比這更超然。

想來想去,臘月的許多生機,也是聚在菜園子里的。“小寒大寒,凍作一團”,天再冷,園子凍不死,那一園子的青蔥總是鮮活着。“冰凍響,蘿蔔長”,蘿蔔堅決和嚴寒叫板,把自己往高處舉、往土裡深掘,最後,身板被錘鍊得結結實實,而甜嫩脆的品質,更叫我們充滿了期待——蘿蔔燉羊肉,饞人喲。

菠菜、矮腳白、包菜、黃心菜、芹菜、芫荽、胡蘿蔔、大蒜、冬莧菜、香蔥、韭菜……也都在勇敢地和季節抗衡,這些尋常的蔬菜,其實是臘月里蟄伏的許多小小的幸福,不驚天動地,卻把每一個日子點綴得不凝滯、不呆板。當然,它們能夠在臘月里天天向上,長得滋潤,還是因為農人們日常細心呵護照料的結果。每一戶農家,對菜園子的拾掇,其實和對待四季里的每一項勞作是一樣的,都含了實實在在的念想,手心裏攥着綿綿的勁道。

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

節能減碳愛地球是景泰電動車的理念,是創立景泰電動車行的初衷,滿意態度更是服務客戶的最高品質,我們的成長來自於你的推薦。

年年歲歲,村裡的柴煙延續着平常的日子,到了臘月,柴煙的身姿和內涵就要豐富很多,因為一個最大的節日在等着:年。

“臘七臘八,腌魚腌鴨。”臘月一項要緊事,就是準備吃貨。月初,魚鴨就差不多腌透了,晴好的日子,每家每戶的屋檐下,油汪汪晾着那一串一串的,受用着陽光溫和的咂摸。整整一個月,農家的灶間難得消停,磨豆腐、蒸米酒、做糍粑,瀰漫的香味香氣,抵消了寒冷侵襲,人心,被烘得暖暖的。

這當口,女人們除了準備關於吃的一切,還要掃揚塵、納鞋底、購年貨、照顧母雞抱窩。農事也沒停,男人們忙着積肥、造肥、修倉、修理農具,等等。“人勤春早”,大伙兒明白,好日子都是頂着風霜雨雪干出來的,臘月,每一個人都在盡最大的本事,把凜凜的冬天過成一個熱烈的期盼。

大年三十晚,臘月只剩下很短的時光。所有的念想都沉澱下來:平安是福,團圓是福,一家樂呵是福。這個晚上,過得快,也過得慢,要祭祖,要放開門炮仗,要守歲,要給晚輩壓歲錢,當然,高潮就是年夜飯了。

不管年景咋樣,也要把年夜飯弄得歡實起來:要湊成雙數的碗,至少要有八個菜,寓意發達;肘子是有的,下了許多功夫,蒸成一大碗,滑嫩,溜光,如琥珀,香氣逼人;魚是有的,紅燒為主,紅辣椒把魚身子蓋滿了,看着就想出汗;雞肯定也是有的,大都用燉的做法,湯黃亮亮的,點綴着桂圓、荔枝、紅枸杞。馬上,一家人圍成一桌,吃上個把小時,吃得熱氣騰騰、熱汗淋漓,吃得滿面紅光光、油光光,滿屋子儘是快活,儘是喜氣。

“野興疏,冬寥落,爐前沉醉酒一壺。”是啊,臘月已經來了,春天也會捂不住的,不如,今夜,在夢裡,潛回老家的山村去,守着一盆炭火,陪着父母,聽他們嘮叨你的小名,嘮叨整整一個晚上……

本站聲明:網站內容來http://www.societynews.cn/html/wh/fq/,如有侵權,請聯繫我們,我們將及時處理

南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

搬家費用:依消費者運送距離、搬運樓層、有無電梯、步行距離、特殊地形、超重物品等計價因素後,評估每車次單

“歌唱北京”展首都新風貌_網頁設計公司

南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

搬家費用:依消費者運送距離、搬運樓層、有無電梯、步行距離、特殊地形、超重物品等計價因素後,評估每車次單

新時代的北京有新時代的歌曲,1月18日晚,原創音樂情景劇“歌唱北京”在中華世紀壇劇場上演,用情景劇、獨唱、合唱、舞蹈等形式展現新北京風貌。

2018年,北京廣播電視檯面向全球發起“歌唱北京”原創歌曲徵集活動,最終產生20首獲獎作品。2019年6月,“歌唱北京”原創歌曲徵集活動再次開啟。這次音樂情景劇中的歌曲就是“歌唱北京”征歌中的優秀作品。

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

節能減碳愛地球是景泰電動車的理念,是創立景泰電動車行的初衷,滿意態度更是服務客戶的最高品質,我們的成長來自於你的推薦。

情景劇以這三位年輕人的視角為切入點,男主角鄭能量是北京青年,女主角唱唱是海歸女孩,京京是一位海外華裔。三人在大興國際機場相遇,鄭能量和唱唱帶着京京領略新北京的風光,遊覽的過程融入了《北京樂章》《我們愛北京》《我愛的城市叫北京》《好客的北京》等歌曲。從前門的特色書店到大柵欄,從南鑼鼓巷到煙袋斜街,這些地標不僅出現在舞台背後的大屏幕上,也出現在“歌唱北京”的歌曲中。歌曲風格也十分多樣,有的有北京大鼓書的風韻,有的是快節奏的說唱,也有深受廣場舞愛好者喜歡的旋律。最終,三位年輕人被北京的高速發展震撼,決定一起為建設新時代的北京而奮鬥。

據悉,2019年度的“歌唱北京”征歌活動仍在進行中,主辦方希望更多市民加入描繪心中的北京,徵集時間將截至2020年3月30日。(記者 韓軒)

本站聲明:網站內容來http://www.societynews.cn/html/wh/fq/,如有侵權,請聯繫我們,我們將及時處理

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

透過選單樣式的調整、圖片的縮放比例、文字的放大及段落的排版對應來給使用者最佳的瀏覽體驗,所以不用擔心有手機版網站兩個後台的問題,而視覺效果也是透過我們前端設計師優秀的空間比例設計,不會因為畫面變大變小而影響到整體視覺的美感。

RabbitMQ 高級應用_網頁設計公司

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

節能減碳愛地球是景泰電動車的理念,是創立景泰電動車行的初衷,滿意態度更是服務客戶的最高品質,我們的成長來自於你的推薦。

 

 

本文是作者原創,版權歸作者所有.若要轉載,請註明出處.

本文RabbitMQ版本為rabbitmq-server-3.7.17,erlang為erlang-22.0.7.請各位去官網查看版本匹配和下載,也可以留言,我發安裝包

 

過期時間TTL(Time To Live)

過期時間TTL表示可以對消息設置預期的時間,在這個時間內都可以被消費者接收穫取;過了之後消息將自動被刪除。RabbitMQ可以對消息和隊列設置TTL。目前有兩種方法可以設置。

  • 第一種方法是通過隊列屬性設置,隊列中所有消息都有相同的過期時間。
  • 第二種方法是對消息進行單獨設置,每條消息TTL可以不同。

如果上述兩種方法同時使用,則消息的過期時間以兩者之間TTL較小的那個數值為準。消息在隊列的生存時間一旦超過設置的TTL值,就稱為dead message被投遞到死信隊列, 消費者將無法再收到該消息。

1. 設置隊列TTL

配置resources\spring\spring-rabbitmq.xml 文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:rabbit="http://www.springframework.org/schema/rabbit"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/rabbit http://www.springframework.org/schema/rabbit/spring-rabbit.xsd">

    <!--定義過期隊列及其屬性,不存在則自動創建-->
    <rabbit:queue id="my_ttl_queue" name="my_ttl_queue" auto-declare="true">
        <rabbit:queue-arguments>
            <!--投遞到該隊列的消息如果沒有消費都將在6秒之後被刪除-->
            <entry key="x-message-ttl" value-type="long" value="6000"/>
        </rabbit:queue-arguments>
    </rabbit:queue>
<rabbit:connection-factory id="connectionFactory" host="192.168.75.163"
port="5672"
username="test01"
password="test01"
virtual-host="/hello"

/>
</beans>

參數 x-message-ttl 的值 必須是非負 32 位整數 (0 <= n <= 2^32-1) ,以毫秒為單位表示 TTL 的值。這樣,值 6000 表示存在於 隊列 中的當前 消息 將最多只存活 6 秒鐘

如果不設置TTL,則表示此消息不會過期。如果將TTL設置為0,則表示除非此時可以直接將消息投遞到消費者,否則該消息會被立即丟棄。

 

然後在測試類中編寫如下方法發送消息到上述定義的隊列:

@RunWith(SpringRunner.class)
@SpringBootTest
public class ProducerTest {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    /**
     * 過期隊列消息
     * 投遞到該隊列的消息如果沒有消費都將在6秒之後被刪除
     */
    @Test
    public void ttlQueueTest(){
        //路由鍵與隊列同名
        rabbitTemplate.convertAndSend("my_ttl_queue", "發送到過期隊列my_ttl_queue,6秒內不消費則不能再被消費。");
    }

}

啟動類中導入配置文件

//導入配置文件
@ImportResource("classpath:/spring/spring-rabbitmq.xml")
@SpringBootApplication
public class ProducerApplication {

    public static void main(String[] args) {
        SpringApplication.run(ProducerApplication.class, args);
    }

}

執行單元測試,看結果

 

 

 6秒后,再看結果

 

 

 

2. 設置消息TTL

消息的過期時間;只需要在發送消息(可以發送到任何隊列,不管該隊列是否屬於某個交換機)的時候設置過期時間即可。

在測試類中編寫如下方法發送消息並設置過期時間到隊列:

/**
     * 過期消息
     * 該消息投遞任何交換機或隊列中的時候;如果到了過期時間則將從該隊列中刪除
     */
    @Test
    public void ttlMessageTest(){
        MessageProperties messageProperties = new MessageProperties();
        //設置消息的過期時間,3秒
        messageProperties.setExpiration("3000");
        Message message = new Message("測試過期消息,3秒鐘過期".getBytes(), messageProperties);
        //路由鍵與隊列同名
        rabbitTemplate.convertAndSend("my_ttl_queue", message);
    }

expiration 字段以微秒為單位表示 TTL 值。且與 x-message-ttl 具有相同的約束條件。因為 expiration 字段必須為字符串類型,broker 將只會接受以字符串形式表達的数字。

當同時指定了 queue 和 message 的 TTL 值,則兩者中較小的那個才會起作用。

 

死信隊列

DLX,全稱為Dead-Letter-Exchange , 可以稱之為死信交換機,也有人稱之為死信郵箱。

當消息在一個隊列中變成死信(dead message)之後,它能被重新發送到另一個交換機中,這個交換機就是DLX ,綁定DLX的隊列就稱之為死信隊列。

消息變成死信,可能是由於以下的原因:

  • 消息被拒絕
  • 消息過期
  • 隊列達到最大長度

DLX也是一個正常的交換機,和一般的交換機沒有區別,它能在任何的隊列上被指定,實際上就是設置某一個隊列的屬性。

當這個隊列中存在死信時,Rabbitmq就會自動地將這個消息重新發布到設置的DLX上去,進而被路由到另一個隊列,即死信隊列。

要想使用死信隊列,只需要在定義隊列的時候設置隊列參數 x-dead-letter-exchange 指定交換機即可。

 

 

具體步驟如下

1. 定義死信交換機

<!--定義定向交換機中的持久化死信隊列,不存在則自動創建-->
<rabbit:queue id="my_dlx_queue" name="my_dlx_queue" auto-declare="true"/>

<!--定義廣播類型交換機;並綁定上述隊列-->
<rabbit:direct-exchange id="my_dlx_exchange" name="my_dlx_exchange" auto-declare="true">
<rabbit:bindings>
<!--綁定路由鍵my_ttl_dlx、my_max_dlx,可以將過期的消息轉移到my_dlx_queue隊列-->
<rabbit:binding key="my_ttl_dlx" queue="my_dlx_queue"/>
<rabbit:binding key="my_max_dlx" queue="my_dlx_queue"/>
</rabbit:bindings>
</rabbit:direct-exchange>

2. 隊列設置死信交換機

<!--定義過期隊列及其屬性,不存在則自動創建-->
<rabbit:queue id="my_ttl_dlx_queue" name="my_ttl_dlx_queue" auto-declare="true">
<rabbit:queue-arguments>
<!--投遞到該隊列的消息如果沒有消費都將在6秒之後被投遞到死信交換機-->
<entry key="x-message-ttl" value-type="long" value="6000"/>
<!--設置當消息過期后投遞到對應的死信交換機-->
<entry key="x-dead-letter-exchange" value="my_dlx_exchange"/>
</rabbit:queue-arguments>
</rabbit:queue>

<!--定義限制長度的隊列及其屬性,不存在則自動創建-->
<rabbit:queue id="my_max_dlx_queue" name="my_max_dlx_queue" auto-declare="true">
<rabbit:queue-arguments>
<!--投遞到該隊列的消息最多2個消息,如果超過則最早的消息被刪除投遞到死信交換機-->
<entry key="x-max-length" value-type="long" value="2"/>
<!--設置當消息過期后投遞到對應的死信交換機-->
<entry key="x-dead-letter-exchange" value="my_dlx_exchange"/>
</rabbit:queue-arguments>
</rabbit:queue>

<!--定義定向交換機 根據不同的路由key投遞消息-->
<rabbit:direct-exchange id="my_normal_exchange" name="my_normal_exchange" auto-declare="true">
<rabbit:bindings>
<rabbit:binding key="my_ttl_dlx" queue="my_ttl_dlx_queue"/>
<rabbit:binding key="my_max_dlx" queue="my_max_dlx_queue"/>
</rabbit:bindings>
</rabbit:direct-exchange>

3. 消息過期的死信隊列測試

/**
     * 過期消息投遞到死信隊列
     * 投遞到一個正常的隊列,但是該隊列有設置過期時間,到過期時間之後消息會被投遞到死信交換機(隊列)
     */
    @Test
    public void dlxTTLMessageTest(){
        rabbitTemplate.convertAndSend(
                "my_normal_exchange",
                "my_ttl_dlx",
                "測試過期消息;6秒過期後會被投遞到死信交換機2222");
    }

運行看結果

 

 6秒后

 

 

4. 消息溢出的死信隊列測試

/**
     * 消息長度超過2,會投遞到死信隊列中
     */
    @Test
    public void dlxMaxMessageTest(){
        rabbitTemplate.convertAndSend(
                "my_normal_exchange",
                "my_max_dlx",
                "發送消息4:消息長度超過2,會被投遞到死信隊列中!");

        rabbitTemplate.convertAndSend(
                "my_normal_exchange",
                "my_max_dlx",
                "發送消息5:消息長度超過2,會被投遞到死信隊列中!");

        rabbitTemplate.convertAndSend(
                "my_normal_exchange",
                "my_max_dlx",
                "發送消息6:消息長度超過2,會被投遞到死信隊列中!");
        
    }

運行,看結果

 

 

 

 上面發送的3條消息中的第1條消息會被投遞到死信隊列中

 

延遲隊列

延遲隊列存儲的對象是對應的延遲消息;所謂“延遲消息” 是指當消息被發送以後,並不想讓消費者立刻拿到消息,而是等待特定時間后,消費者才能拿到這個消息進行消費。

在RabbitMQ中延遲隊列可以通過 過期時間 + 死信隊列 來實現

 

 

延遲隊列的應用場景;如:

  • 在電商項目中的支付場景;如果在用戶下單之後的幾十分鐘內沒有支付成功;那麼這個支付的訂單算是支付失敗,要進行支付失敗的異常處理(將庫存加回去),這時候可以通過使用延遲隊列來處理
  • 在系統中如有需要在指定的某個時間之後執行的任務都可以通過延遲隊列處理

具體代碼不演示了

 

消息確認機制

確認並且保證消息被送達,提供了兩種方式:發布確認和事務。(兩者不可同時使用)在channel為事務時,不可引入確認模式;同樣channel為確認模式下,不可使用事務。

1 發布確認

消息發送成功確認

connectionFactory 中啟用消息確認:

<rabbit:connection-factory id="connectionFactory" host="192.168.75.163"
                               port="5672"
                               username="test01"
                               password="test01"
                               virtual-host="/hello"
                               publisher-confirms="true"
    />

配置消息確認回調方法如下:

<!-- 消息回調處理類 -->
<bean id="confirmCallback" class="com.itheima.rabbitmq.MsgSendConfirmCallBack"/>
<!--定義rabbitTemplate對象操作可以在代碼中方便發送消息-->
<!-- confirm-callback="confirmCallback" 表示:消息失敗回調 -->
<rabbit:template id="rabbitTemplate" connection-factory="connectionFactory" 
        confirm-callback="confirmCallback"/>

消息確認回調方法如下:

public class MsgSendConfirmCallBack implements RabbitTemplate.ConfirmCallback {
    public void confirm(CorrelationData correlationData, boolean ack, String cause) {
        if (ack) {
            System.out.println("消息確認成功....");
        } else {
            //處理丟失的消息
            System.out.println("消息確認失敗," + cause);
        }
    }
}

我們手動建一個spring_queue隊列.並測試如下:

 @Test
    public void queueTest(){
        //路由鍵與隊列同名
        rabbitTemplate.convertAndSend("spring_queue", "只發隊列spring_queue的消息。");
    }

查看結果

 

 

 

 消息發送失敗回調

connectionFactory 中啟用回調:

!-- publisher-returns="true" 表示:啟用了失敗回調 -->
<rabbit:connection-factory id="connectionFactory" host="${rabbitmq.host}"
        port="${rabbitmq.port}"
        username="${rabbitmq.username}"
        password="${rabbitmq.password}"
        virtual-host="${rabbitmq.virtual-host}"
        publisher-returns="true" />

配置消息失敗回調方法如下:

<!-- 消息失敗回調類 -->
<bean id="sendReturnCallback" class="com.itheima.rabbitmq.MsgSendReturnCallback"/>
<!-- return-callback="sendReturnCallback" 表示:消息失敗回調 ,同時需配置mandatory="true",否則消息則丟失-->
<rabbit:template id="rabbitTemplate" connection-factory="connectionFactory"
        confirm-callback="confirmCallback" return-callback="sendReturnCallback" 
        mandatory="true"/>

注意:同時需配置mandatory=”true”,否則消息則丟失

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

透過選單樣式的調整、圖片的縮放比例、文字的放大及段落的排版對應來給使用者最佳的瀏覽體驗,所以不用擔心有手機版網站兩個後台的問題,而視覺效果也是透過我們前端設計師優秀的空間比例設計,不會因為畫面變大變小而影響到整體視覺的美感。

 

消息失敗回調方法如下:

public class MsgSendReturnCallback implements RabbitTemplate.ReturnCallback {
    public void returnedMessage(Message message, int i, String s, String s1, String s2) {
        String msgJson  = new String(message.getBody());
        System.out.println("Returned Message:"+msgJson);
    }
}

模擬消息發送失敗,功能測試如下:

@Test
public void testFailQueueTest() throws InterruptedException {
    //exchange 正確,queue 錯誤 ,confirm被回調, ack=true; return被回調 replyText:NO_ROUTE
    amqpTemplate.convertAndSend("test_fail_exchange", "", "測試消息發送失敗進行確認應答。");
}

失敗回調結果如下:

 

 

事務支持

場景:業務處理伴隨消息的發送,業務處理失敗(事務回滾)后要求消息不發送。rabbitmq 使用調用者的外部事務,通常是首選,因為它是非侵入性的(低耦合)。

外部事務的配置

<rabbit:template id="rabbitTemplate"
                     connection-factory="connectionFactory"

                     mandatory="true"
                     channel-transacted="true"
    />

    <!--平台事務管理器-->
    <bean id="transactionManager" class="org.springframework.amqp.rabbit.transaction.RabbitTransactionManager">
        <property name="connectionFactory" ref="connectionFactory"/>
    </bean>

測試類或者測試方法上加入@Transactional註解

   @Test
    @Transactional //開啟事務
    //@Rollback(false)//在測試的時候,需要手動的方式制定回滾的策略
    public void queueTest2(){
        //路由鍵與隊列同名
        rabbitTemplate.convertAndSend("spring_queue", "只發隊列spring_queue的消息--02222222222222222222。");
        System.out.println("----------------dosoming:可以是數據庫的操作,也可以是其他業務類型的操作---------------");
        //模擬業務處理失敗
        //System.out.println(1/0);
        rabbitTemplate.convertAndSend("spring_queue", "只發隊列spring_queue的消息--02。");
    }

運行看結果

 

 

 

 

 

 因為是測試類,所以spring自動回滾了,需要我們手動禁止回滾

   @Test
    @Transactional //開啟事務
    @Rollback(false)//在測試的時候,需要手動的方式制定回滾的策略
    public void queueTest2(){
        //路由鍵與隊列同名
        rabbitTemplate.convertAndSend("spring_queue", "只發隊列spring_queue的消息--02222222222222222222。");
        System.out.println("----------------dosoming:可以是數據庫的操作,也可以是其他業務類型的操作---------------");
        //模擬業務處理失敗
        //System.out.println(1/0);
        rabbitTemplate.convertAndSend("spring_queue", "只發隊列spring_queue的消息--02。");
    }

再執行一次測試類,查看結果

 

 

 我們手動弄個異常,再試一次

  @Test
    @Transactional //開啟事務
    @Rollback(false)//在測試的時候,需要手動的方式制定回滾的策略
    public void queueTest2(){
        //路由鍵與隊列同名
        rabbitTemplate.convertAndSend("spring_queue", "只發隊列spring_queue的消息--02222222222222222222。");
        System.out.println("----------------dosoming:可以是數據庫的操作,也可以是其他業務類型的操作---------------");
        //模擬業務處理失敗
        System.out.println(1/0);
        rabbitTemplate.convertAndSend("spring_queue", "只發隊列spring_queue的消息--02。");
    }

看結果

 

 

 這裏4條是因為我手動禁止了回滾

結果應該是沒問題的,就不測試了

 

消息追蹤

1.消息追蹤啟用與查看

消息中心的消息追蹤需要使用Trace實現,Trace是Rabbitmq用於記錄每一次發送的消息,方便使用Rabbitmq的開發者調試、排錯。可通過插件形式提供可視化界面。

Trace啟動後會自動創建系統Exchange:amq.rabbitmq.trace ,每個隊列會自動綁定該Exchange,綁定后發送到隊列的消息都會記錄到Trace日誌。

 

查看插件列表

rabbitmq-plugins list

 

 

 

 

rabbitmq啟用trace插件

rabbitmq-plugins enable rabbitmq_tracing

命令集 描述
rabbitmq-plugins list 查看插件列表
rabbitmq-plugins enable rabbitmq_tracing rabbitmq啟用trace插件
rabbitmqctl trace_on 打開trace的開關
rabbitmqctl trace_on -p test01 打開trace的開關(itcast為需要日誌追蹤的vhost)
rabbitmqctl trace_off 關閉trace的開關
rabbitmq-plugins disable rabbitmq_tracing rabbitmq關閉Trace插件
rabbitmqctl set_user_tags test01 administrator 只有administrator的角色才能查看日誌界面

 

 

 

 

 

 

 

 

 

 

 安裝插件並開啟 trace_on 之後,會發現多個 exchange:amq.rabbitmq.trace ,類型為:topic。

 

 

2 日誌追蹤

首先重新登錄管理控制台

 

 

第一步:發送消息

@Test
    public void queueTest3() throws InterruptedException {
        rabbitTemplate.convertAndSend("spring_queue", "只發隊列spring_queue的消息--01。");
    }

 

 第二步:查看trace

第三步:點擊Tracing查看Trace log files

 

 

第四步:點擊itest-log.log確認消息軌跡正確性

 

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

搬家費用:依消費者運送距離、搬運樓層、有無電梯、步行距離、特殊地形、超重物品等計價因素後,評估每車次單

剪窗花過年_網頁設計公司

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

節能減碳愛地球是景泰電動車的理念,是創立景泰電動車行的初衷,滿意態度更是服務客戶的最高品質,我們的成長來自於你的推薦。

  圖為中國剪紙。
  劉建華攝(影像中國)

  圖為北京前門大街的迎春燈籠。
  郭俊鋒攝(影像中國)

  過春節,一般年前最忙。到大年初一,人們就可以盡享清福,闔家歡樂了。年前,男主人、女主人都要外出忙着採購年貨,一些婦女和孩子留在家裡,洒掃庭除之後,圍坐在炕頭和桌前,開始剪窗花了。

  這樣的風俗,有兩方面原因。

  一是,剪出的窗花貼到窗上,和大門兩旁貼的春聯、大門中央貼的門神、屋子牆上貼的福字,和房檐門楣上掛的吊錢,一定都要在大年三十之前完成,才算是過年的樣子。清末竹枝詞里說:“掃室糊棚舊換新,家家戶戶貼宜春。”其中的“貼”字說的就是準備過年這樣必需的程式。

  另一面,和過年的時候家裡人不許動刀剪的民俗有關(還有不許掃地倒臟土等,都是防止不吉利的說法)。清時詩人查慎行有詩:“巧裁幡勝試新羅,畫彩描金作鬧蛾。從此刀剪閑一月,閨中針線歲前多。”這裏說的巧裁新羅,畫彩描金,就包含有剪窗花,從此刀剪閑一月,後來改成到正月十五;再後來到破五;現在,已經徹底沒有這個風俗了。

  春聯、門神、福字、窗花和吊錢,這五項過年之前之必備,我稱之為過年五件套。和後來結婚時候一度流行的手錶、自行車和大衣櫃這三件套的說法相類似。只是,結婚三件套,早已被時代的發展所淘汰,而過年這五件套,幾百年過去了,至今依然風俗變化不大,除了吊錢如今在北京見到的少了,其餘四種,仍然在過年前看許多人家在忙乎張羅。因為這是過年必備的慶祝儀式的硬件標準。可見,民俗的力量,在潛移默化中,代代傳承。

  到正月十五燈節之前,再加上各家大門前掛上一盞紅燈籠,就是過年必備的六件套。這六件套,全部都是紅顏色,過年前後這一段時間里,全國各地,無論鄉間,還是城市,到處是這樣一片中國紅,那才叫過年,是過年的色彩。如果說過年到處是這樣紅彤彤一片的海洋翻滾,那麼,窗花是其中奪目的浪花簇擁。

  過去的歲月里,年前要準備的這五件套,除了門神尉遲恭秦叔寶的形象複雜,要到外面買那種木刻現成的之外,其餘四件,普通百姓人家,都是要自己動手做的。這和年三十晚上的那頓餃子必須得全家動手包一樣,參与在過年的程式之中,才像是過年的樣子。普通人家剪窗花,是和貼春聯、掛吊錢,包括做門神、寫福字一樣,都只用普通的大紅紙。各家都須到紙店裡買大紅紙。大紅紙暢銷得很。

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

透過選單樣式的調整、圖片的縮放比例、文字的放大及段落的排版對應來給使用者最佳的瀏覽體驗,所以不用擔心有手機版網站兩個後台的問題,而視覺效果也是透過我們前端設計師優秀的空間比例設計,不會因為畫面變大變小而影響到整體視覺的美感。

  那時候,家附近有兩家老字號的紙店,一家是南紙店,叫公興號,在大柵欄東口路南;一家是京紙店,叫敬庄號,在興隆街,我們大院後身。家裡人一般都將這項任務交給我們小孩子,我們都願意舍近求遠去公興號,一是那裡店大,紙的品種多;二來路過前門大街,到處是賣各種小吃的店鋪和攤子,我們可以將買紙剩下的錢買點兒吃的解饞。家裡人都囑咐我們買那種便宜的大紅紙。其實,不用囑咐,我們都會買最便宜的,這樣剩下的錢會多點兒,買的吃食也會多點兒呢。

  有一陣子,公興號流行賣一種電光紙,我們又叫它玻璃紙,因為它像玻璃一樣反光,一閃一閃。我們都喜歡,便買回家。家裡大人不樂意,看着就撇嘴,讓我們立馬兒拿回去換紙,一準覺得還是傳統的那種大紅紙好。

  過去年月里普通人家房子的紙窗,貼的都是高粱紙,很薄,透光性好。傳統的大紅紙也很薄,做成窗花,貼在這樣的花格紙窗上,很是四襯適合。清末《燕都雜詠》有一首說:“油花窗紙換,掃舍又新年。戶寫宜春字,囊分壓歲錢。”詩後有注:“紙繪人物,油之,剪貼窗上,名‘窗花’。”詩中所說的油花窗紙,指的應該就是這種高粱紙,紅紅的窗花貼在上面,紅白相映,屋裡屋外,看着都透亮,紅艷艷的,顯得很喜興。電光紙厚,貼在這樣的花格紙窗上,不僅不透亮,還反光,沒有那種裡外通透的感覺。確實是什麼衣配什麼人,什麼鞍配什麼馬,傳統的窗花用紙,和老式的紙窗兩兩相宜。老祖宗傳下來的玩意兒,有它的道理。

  後來,經濟條件好些了,各家的窗子換成玻璃的,還是覺得貼這種傳統大紅紙剪成的窗花好看。那種電光紙,到底沒能剪成窗花,亮相在我們的窗戶上。

  窗花,是老祖宗傳下來的,既是手藝,也是民俗;既可以是結婚時的裝點,更形成了過年必不可少的一項內容。窗花的歷史悠久,有人說自漢代發明了紙張之後就有了窗花,這我不大相信,紙張剛剛出現的時候,應該很貴,不可能普遍用於窗花。有人說南北朝時對馬團花和對猴團花中就有了鋸齒法和月牙法等古老的剪紙法;有人說唐朝就有,有李商隱的詩為證:“鏤金作勝傳荊俗,剪綵為人起晉風”;也有人說窗花流行於宋元之後……總之,窗花的歷史悠久。

  我私下猜想,窗花最初是用刀刻,然後轉化為剪裁。刀刻出的圖案,應該受到過更早時的石刻或青銅器的雕刻影響,藝術總是相通的,相互影響和借鑒是存在的。從石刻到剪紙,從刀到剪,只是工具和材料的變化而已。剪和刻的區別,還在於剪是要把紙先折成幾疊,是在石頭上無法做到的。別看只是這樣看似簡單的幾疊,卻像變魔術一樣,讓剪紙變成了獨特的藝術。

  窗花,應該是剪紙的前身。窗花也好,剪紙也好,不像石刻或青銅器雕刻,多在王公貴族那邊,而是更多在民間,其民間的元素更多更濃。窗花,又是農耕時代的產物,所以,它的內容更多的是花草魚蟲、飛禽走獸、農事稼穡、民間傳說、神話人物,以至後來還有八仙過海、五福捧壽等很多戲劇內容,可以說是花樣繁多,應有盡有。只有正月十五燈節時的彩燈上描繪的內容,可以和窗花有一拼。燈上的圖案,在窗花上大多可以一一找到對應,只不過,在窗花上刪繁就簡,都變成大紅紙一色的紅。這便是窗花獨到之處,一色的紅,配窗子一色的白,如果過年期間趕上一場大雪,紅白對比得格外強烈,就更漂亮了。

  民間藏龍卧虎,窗花有簡有繁。有的很豐富,我從來沒有見過。前面所引的《燕都雜詠》詩后還有一注,說有這樣的窗花,是“或以陽起石揭薄片,繪花為之”。這種類似拓印式的窗花,我沒見過。《帝京風物略》中說:“門窗貼紅紙葫蘆,曰收瘟鬼。”這風俗和年三十之夜踩松柏枝謂之驅鬼的意思是一樣的。大年三十的夜晚,踩松柏枝,我沒有踩過,那時我們院子里有人買來秫秸稈,讓我們小孩子踩,意思是一樣的。但是,這種貼紅紙葫蘆的窗花,我也沒見過。《燕京雜記》中說:“剪紙不斷,供於祖前,謂之‘阡張’。”過年期間,如此誇張的剪紙,是窗花的變異,我更是沒見過。

  小時候,我看鄰家的小姐姐或阿姨剪窗花,順便要幾朵,拿回家貼在窗上。我有了兒子之後,孩子小時候磨我教他剪窗花,我不會,便把他推給我母親,告訴他:奶奶會,你找奶奶去!其實,奶奶只剪過鞋樣子,哪裡會剪窗花?但被孩子磨得沒法子了,只好從針線笸籮里拿出剪子,把大紅紙一折好幾疊,便開始隨便亂剪一通。誰想到,兒子把紅紙抖摟開一看,儘管不知道剪的是什麼圖案,但那樣像抽象派的圖案,還挺新鮮,挺好看呢!這樣剪窗花,一點兒都不難嘛,兒子抄起剪刀,也開始學奶奶的樣子,剪出一床窗花來。我家那年春節的窗戶上,貼的全是奶奶和她的小孫子剪的窗花。

  流年似水,一晃又到春節。兒子的兩個孩子,一個八歲,一個十歲了。他們跟爸爸新學會了剪紙,年前剪了一堆的窗花,比他們的爸爸當年剪得有章法多了。雖然人在國外,但兩人準備春節前送給每個同學一個窗花,讓他們那些外國同學也知道中國人過年貼的窗花是什麼樣子。視頻通話的時候,我讓他們兩人先別忙着把窗花送同學,一人選出自己最得意的一個窗花,先送給我。今年貼在我家的窗上,他們和他們的窗花,陪我們老兩口一起過年。

本站聲明:網站內容來http://www.societynews.cn/html/wh/fq/,如有侵權,請聯繫我們,我們將及時處理

南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

搬家費用:依消費者運送距離、搬運樓層、有無電梯、步行距離、特殊地形、超重物品等計價因素後,評估每車次單

CTR學習筆記&代碼實現6-深度ctr模型 後浪 xDeepFM/FiBiNET_網頁設計公司

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

透過選單樣式的調整、圖片的縮放比例、文字的放大及段落的排版對應來給使用者最佳的瀏覽體驗,所以不用擔心有手機版網站兩個後台的問題,而視覺效果也是透過我們前端設計師優秀的空間比例設計,不會因為畫面變大變小而影響到整體視覺的美感。

xDeepFM用改良的DCN替代了DeepFM的FM部分來學習組合特徵信息,而FiBiNET則是應用SENET加入了特徵權重比NFM,AFM更進了一步。在看兩個model前建議對DeepFM, Deep&Cross, AFM,NFM都有簡單了解,不熟悉的可以看下文章最後其他model的博客鏈接。

以下代碼針對Dense輸入更容易理解模型結構,針對spare輸入的代碼和完整代碼
https://github.com/DSXiangLi/CTR

xDeepFM

模型結構

看xDeepFM的名字和DeepFM相似都擁有Deep和Linear的部分,只不過把DeepFM中用來學習二階特徵交互的FM部分替換成了CIN(Compressed Interactino Network)。而CIN是在Deep&Cross的DCN上進一步改良的得到。整體模型結構如下

我們重點看下CIN的部分,和paper的notation保持一致,有m個特徵,每個特徵Embedding是D維,第K層的CIN有\(H_k\)個unit。CIN第K層的計算分為3個部分分別對應圖a-c:

  1. 向量兩兩做element-wise product, 時間複雜度\(O(m*H_{k-1}*D)\)
    對輸入層和第K-1層輸出,做element-wise乘積進行兩兩特徵交互,得到\(m*H_{k-1}\)個D維向量矩陣,如果CIN只有一層,則和FM, NFM,AFM的第一步相同。FM 直接聚合成scaler,NFM沿D進行sum_pooling,而AFM加入Attention沿D進行weighted_pooling。忽略batch的矩陣dimension變化如下

\[z^k = x^0 \odot x^{k-1} = (D * m* 1) \odot (D * 1* H_{k-1}) = D * m*H_{k-1} \]

  1. Feature Map,空間複雜度\(O(H_k *H_{k-1} *m)\),時間複雜度\(O(H_k *H_{k-1} *m*D)\)
    \(W_k \in R^{H_{k-1}*m *H_k}\) 是第K層的權重向量,可以理解為沿Embedding做CNN。每個Filter對所有兩兩乘積的向量進行加權求和得到 \(1*D\)的向量 一共有\(H_k\)個channel,輸出\(H_k * D\)的矩陣向量。

\[w^k \bullet z^k = (H_k *H_{k-1} *m)* (m*H_{k-1}*D) = H_k *D \]

  1. Sum Pooling
    CIN對每層的輸出沿Dimension進行sum pooling,得到\(H_k*1\)的輸出,然後把每層輸出concat以後作為CIN部分的輸出。

CIN每一層的計算如上,T層CIN每一層都是上一次層的輸出和第一層的輸入進行交互得到更高一階的交互信息。假設每層維度一樣\(H_k=H\), CIN 部分整體時間複雜度是\(O(TDmH^2)\),空間複雜度來自每層的Filter權重\(O(TmH^2)\)

CIN保留DCN的任意高階和參數共享,兩個主要差別是

  • DCN是bit-wise,CIN是vector-wise。DCN在做向量乘積時不區分Field,直接對所有Field拼接成的輸入(m*D)進行外積。而CIN考慮Field,兩兩vector進行乘積
  • DCN使用了ResNet因為多項式的核心只用輸出最後一層,而CIN則是每層都進行pooling后輸出

CIN的設計還是很巧妙滴,不過。。。吐槽小分隊上線: CIN不論是時間複雜度還是空間複雜度都比DCN要高,感覺更容易過擬合。至於說vector-wise的向量乘積要比bit-wise的向量乘積要好,這。。。至少bit-wise可以不限制embedding維度一致, 但vector-wise嘛我實在有些理解無能,明白的童鞋可以comment一下

代碼實現

def cross_op(xk, x0, layer_size_prev, layer_size_curr, layer, emb_size, field_size):
    # Hamard product: ( batch * D * HK-1 * 1) * (batch * D * 1* H0) -> batch * D * HK-1 * H0
    zk = tf.matmul( tf.expand_dims(tf.transpose(xk, perm = (0, 2, 1)), 3),
                    tf.expand_dims(tf.transpose(x0, perm = (0, 2, 1)), 2))

    zk = tf.reshape(zk, [-1, emb_size, field_size * layer_size_prev]) # batch * D * HK-1 * H0 -> batch * D * (HK-1 * H0)
    add_layer_summary('zk_{}'.format(layer), zk)

    # Convolution with channel = HK: (batch * D * (HK-1*H0)) * ((HK-1*H0) * HK)-> batch * D * HK
    kernel = tf.get_variable(name = 'kernel{}'.format(layer),
                             shape = (field_size * layer_size_prev, layer_size_curr))
    xkk = tf.matmul(zk, kernel)
    xkk = tf.transpose(xkk, perm = [0,2,1]) # batch * HK * D
    add_layer_summary( 'Xk_{}'.format(layer), xkk )
    return xkk


def cin_layer(x0, cin_layer_size, emb_size, field_size):
    cin_output_list = []

    cin_layer_size.insert(0, field_size) # insert field dimension for input
    with tf.variable_scope('Cin_component'):
        xk = x0
        for layer in range(1, len(cin_layer_size)):
            with tf.variable_scope('Cin_layer{}'.format(layer)):
                # Do cross
                xk = cross_op(xk, x0, cin_layer_size[layer-1], cin_layer_size[layer],
                              layer, emb_size, field_size ) # batch * HK * D
                # sum pooling on dimension axis
                cin_output_list.append(tf.reduce_sum(xk, 2)) # batch * HK

    return tf.concat(cin_output_list, axis=1)

@tf_estimator_model
def model_fn_dense(features, labels, mode, params):
    dense_feature, sparse_feature = build_features()
    dense_input = tf.feature_column.input_layer(features, dense_feature)
    sparse_input = tf.feature_column.input_layer(features, sparse_feature)

    # Linear part
    with tf.variable_scope('Linear_component'):
        linear_output = tf.layers.dense( sparse_input, units=1 )
        add_layer_summary( 'linear_output', linear_output )

    # Deep part
    dense_output = stack_dense_layer( dense_input, params['hidden_units'],
                               params['dropout_rate'], params['batch_norm'],
                               mode, add_summary=True )
    # CIN part
    emb_size = dense_feature[0].variable_shape.as_list()[-1]
    field_size = len(dense_feature)
    embedding_matrix = tf.reshape(dense_input, [-1, field_size, emb_size]) # batch * field_size * emb_size
    add_layer_summary('embedding_matrix', embedding_matrix)

    cin_output = cin_layer(embedding_matrix, params['cin_layer_size'], emb_size, field_size)

    with tf.variable_scope('output'):
        y = tf.concat([dense_output, cin_output,linear_output], axis=1)
        y = tf.layers.dense(y, units= 1)
        add_layer_summary( 'output', y )

    return y

FiBiNET

模型結構

看FiBiNET前可以先了解下Squeeze-and-Excitation Network,感興趣可以看下這篇博客Squeeze-and-Excitation Networks。

FiBiNET的主要創新是應用SENET學習每個特徵的重要性,加權得到新的Embedding矩陣。在FiBiNET之前,AFM,PNN,DCN和上面的xDeepFM都是在特徵交互之後才用attention, 加權等方式學習特徵交互的權重,而FiBiNET在保留這部分的同時,在Embedding部分就考慮特徵自身的權重。模型結構如下

原始Embedding,和經過SENET調整過權重的新Embedding,在Bilinear-interaction層學習二階交互特徵,拼接后,再經過MLP進一步學習高階特徵。和paper notation保持一致(啊啊啊大家能不能統一下notation搞的我自己看自己的註釋都蒙圈),f個特徵,k維embedding

SENET層

SENET層學習每個特徵的權重對Embedding進行加權,分為以下3步

南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

搬家費用:依消費者運送距離、搬運樓層、有無電梯、步行距離、特殊地形、超重物品等計價因素後,評估每車次單

  1. Squeeze
    \(f*k\)的Embedding矩陣壓縮成\(f*1\), 壓縮方式不固定,SENET原paper用的max_pooling,作者用的sum_pooling,感覺這裏壓縮方式應該取決於Embedding的信息表達

\[\begin{align} E &= [e_1,…,e_f] \\ Z &= [z_1,…,z_f] \\ z_i &= F_{squeeze}(e_i) = \frac{1}{k}\sum_{i=1}^K e_i \\ \end{align} \]

  1. Excitation
    Excitation是一個兩層的全連接層,通過先降維再升維的方式過濾一些無用特徵,降維的幅度通過額外變量\(r\)來控制,第一層權重\(W_1 \in R^{f*f/r}\),第二層權重\(W_2 \in R^{f/r*f}\)。這裏r越高,壓縮的幅度越高,最終的權重會更集中,反之會更分散。

\[A = \sigma_2(W_2·\sigma_1(W_1·Z)) \]

  1. Re-weight
    最後一步就是用Excitation得到的每個特徵的權重對Embedding進行加權得到新Embedding

\[E_{new} = F_{Reweight}(A,E) = [a_1·e_1, …,a_f·e_f ] \]

在收入數據集上進行嘗試,r=2時會有46%的embedding特徵權重為0,所以SENET會在特徵交互前先過濾部分對target無用的特徵來增加有效特徵的權重

Bilinear-Interaction層

作者提出內積和element-wise乘積都不足以捕捉特徵交互信息,因此進一步引入權重W,以下面的方式進行特徵交互

\[v_i · W \odot v_j \]

其中W有三種選擇,可以所有特徵交互共享一個權重矩陣(Field-All),或者每個特徵和其他特徵的交互共享權重(Field-Each), 再或者每個特徵交互一個權重(Field-Interaction) 具體的優劣感覺需要casebycase來試,不過一般還是照着數據越少參數越少的邏輯來整。

原始Embedding和調整權重后的Embedding在Bilinear-Interaction學習交互特徵后,拼接成shallow 層,再經過全連接層來學習更高階的特徵交互。後面的屬於常規操作這裏就不再細說。

我們不去吐槽FiBiNET可以加入wide&deep框架來捕捉低階特徵信息和任意高階信息,更多把FiBiNET提供的SENET特徵權重的思路放到自己的工具箱中就好。

代碼實現

def Bilinear_layer(embedding_matrix, field_size, emb_size, type, name):
    # Bilinear_layer: combine inner and element-wise product
    interaction_list = []
    with tf.variable_scope('BI_interaction_{}'.format(name)):
        if type == 'field_all':
            weight = tf.get_variable( shape=(emb_size, emb_size), initializer=tf.truncated_normal_initializer(),
                                      name='Bilinear_weight_{}'.format(name) )
        for i in range(field_size):
            if type == 'field_each':
                weight = tf.get_variable( shape=(emb_size, emb_size), initializer=tf.truncated_normal_initializer(),
                                          name='Bilinear_weight_{}_{}'.format(i, name) )
            for j in range(i+1, field_size):
                if type == 'field_interaction':
                    weight = tf.get_variable( shape=(emb_size, emb_size), initializer=tf.truncated_normal_initializer(),
                                          name='Bilinear_weight_{}_{}_{}'.format(i,j, name) )
                vi = tf.gather(embedding_matrix, indices = i, axis =1, batch_dims =0, name ='v{}'.format(i)) # batch * emb_size
                vj = tf.gather(embedding_matrix, indices = j, axis =1, batch_dims =0, name ='v{}'.format(j)) # batch * emb_size
                pij = tf.matmul(tf.multiply(vi,vj), weight) # bilinear : vi * wij \odot vj
                interaction_list.append(pij)

        combination = tf.stack(interaction_list, axis =1 ) # batch * emb_size * (Field_size * (Field_size-1)/2)
        combination = tf.reshape(combination, shape = [-1, int(emb_size * (field_size * (field_size-1) /2)) ]) # batch * ~
        add_layer_summary( 'bilinear_output', combination )

    return combination


def SENET_layer(embedding_matrix, field_size, emb_size, pool_op, ratio):
    with tf.variable_scope('SENET_layer'):
        # squeeze embedding to scaler for each field
        with tf.variable_scope('pooling'):
            if pool_op == 'max':
                z = tf.reduce_max(embedding_matrix, axis=2) # batch * field_size * emb_size -> batch * field_size
            else:
                z = tf.reduce_mean(embedding_matrix, axis=2)
            add_layer_summary('pooling scaler', z)

        # excitation learn the weight of each field from above scaler
        with tf.variable_scope('excitation'):
            z1 = tf.layers.dense(z, units = field_size//ratio, activation = 'relu')
            a = tf.layers.dense(z1, units= field_size, activation = 'relu') # batch * field_size
            add_layer_summary('exciitation weight', a )

        # re-weight embedding with weight
        with tf.variable_scope('reweight'):
            senet_embedding = tf.multiply(embedding_matrix, tf.expand_dims(a, axis = -1)) # (batch * field * emb) * ( batch * field * 1)
            add_layer_summary('senet_embedding', senet_embedding) # batch * field_size * emb_size

        return senet_embedding

@tf_estimator_model
def model_fn_dense(features, labels, mode, params):
    dense_feature, sparse_feature = build_features()
    dense_input = tf.feature_column.input_layer(features, dense_feature)
    sparse_input = tf.feature_column.input_layer(features, sparse_feature)

    # Linear part
    with tf.variable_scope('Linear_component'):
        linear_output = tf.layers.dense( sparse_input, units=1 )
        add_layer_summary( 'linear_output', linear_output )

    field_size = len(dense_feature)
    emb_size = dense_feature[0].variable_shape.as_list()[-1]
    embedding_matrix = tf.reshape(dense_input, [-1, field_size, emb_size])

    # SENET_layer to get new embedding matrix
    senet_embedding_matrix = SENET_layer(embedding_matrix, field_size, emb_size,
                                         pool_op = params['pool_op'], ratio= params['senet_ratio'])

    # combination layer & BI_interaction
    BI_org = Bilinear_layer(embedding_matrix, field_size, emb_size, type = params['bilinear_type'], name = 'org')
    BI_senet = Bilinear_layer(senet_embedding_matrix, field_size, emb_size, type = params['bilinear_type'], name = 'senet')

    combination_layer = tf.concat([BI_org, BI_senet] , axis =1)

    # Deep part
    dense_output = stack_dense_layer(combination_layer, params['hidden_units'],
                               params['dropout_rate'], params['batch_norm'],
                               mode, add_summary=True )

    with tf.variable_scope('output'):
        y = dense_output + linear_output
        add_layer_summary( 'output', y )

    return y

CTR學習筆記&代碼實現系列

https://github.com/DSXiangLi/CTR
CTR學習筆記&代碼實現1-深度學習的前奏 LR->FFM
CTR學習筆記&代碼實現2-深度ctr模型 MLP->Wide&Deep
CTR學習筆記&代碼實現3-深度ctr模型 FNN->PNN->DeepFM
CTR學習筆記&代碼實現4-深度ctr模型 NFM/AFM
CTR學習筆記&代碼實現5-深度ctr模型 DeepCrossing -> Deep&Cross

Ref

  1. Jianxun Lian, 2018, xDeepFM: Combining Explicit and Implicit Feature Interactions for Recommender Systems
  2. Tongwen Huang, 2019, FiBiNET: Combining Feature Importance and Bilinear feature Interaction for Click-Through Rate Prediction
  3. Jie Hu, 2017, Squeeze-and-Excitation Networks
  4. https://zhuanlan.zhihu.com/p/72931811
  5. https://zhuanlan.zhihu.com/p/79659557
  6. https://zhuanlan.zhihu.com/p/57162373
  7. https://github.com/qiaoguan/deep-ctr-prediction

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

節能減碳愛地球是景泰電動車的理念,是創立景泰電動車行的初衷,滿意態度更是服務客戶的最高品質,我們的成長來自於你的推薦。

紫米 ZMI 無線充車載支架(自動版)通過 NCC 認證,近期將在台開賣_網頁設計公司

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

節能減碳愛地球是景泰電動車的理念,是創立景泰電動車行的初衷,滿意態度更是服務客戶的最高品質,我們的成長來自於你的推薦。

對於時時呵護手機,或者注重車室整體質感有相當要求的車主來說,即便只是選購款車載支架也是需要好好慎選一番才行。去年八月初,小米生態鏈企業 ZMI(紫米)推出了一款支援自動夾緊、 採用 Alcantara 材質表面的高質感無線車載支架,最近它也悄悄由紫米授權經銷 Kamera 佳美能科技申請通過 NCC 認證,未來也將在台灣開賣。

▲圖片來源:ZMI 紫米

紫米 ZMI 無線充車載支架(自動版)通過 NCC 認證,近期將在台開賣

上週,在 NCC 認證通過的資料庫中出現了一款 ZMI 型號 WCJ11 的無線車充設備,經比對附件外觀和產品型號後確認它就是去年八月初在中國率先發表的「ZMI 無線車充車在支架自動版」,申請的廠商正是紫米在台灣的授權經銷 Kamera 佳美能科技。
即便這款產品可能在些網拍平台有其他人購入販售,但建議如果對這款產品有興趣的讀者,為了產品的品質和售後服務,還是選購未來 Kamera 的公司貨才有保障。

▲圖片來源:NCC

ZMI 車載無線充車載支架(自動版),顧名思義就是他支持自動夾緊功能,藉由內建紅外線感應器和馬達,在手機靠近時兩側的夾臂可自動展開、鎖緊,讓手機可輕鬆放入進行充電。要取下手機時,輕觸側面按鍵即可單手取出手機。
另外,這款車載支架的夾臂張開的寬度可達 81.5mm ,理論上來說絕大多數的智慧型手機都能適用,但像是目前市面最常見的「大手機」 iPhone 12 Pro Max 裸機寬度為 78.1mm ,若要使用這款產品則切記不要使用過於寬厚的手機保護殼。

▲圖片來源:ZMI 紫米

多數車載支架在與手機背面接觸的表面都採用塑料材質,如果相當保護手機、害怕刮傷的用戶難免會擔心長久下來讓手機產生刮痕。而 ZMI 無線充車載支架(自動版)採用 Alcantara  的超纖面料作為充電面板,柔軟、耐磨、手感好的特性,也常在進口豪華車、超跑內裝常見到這類材質。
車載支架固定採用三角結構能穩固防止路面顛簸,而自動鎖緊也能加強手機牢牢固定在車載支架上進行無線充電,無線充電有效感應距離達 4mm ,即便使用保護殼也能進行充電。

▲圖片來源:ZMI 紫米

雖然這款車載支架最高僅支持到 10W 的無線快充,不過撇除小米、華為一些特殊機型,其實對於目前普遍支持 Qi 無線充電的主流手機來說, 10W 無線充電已經綽綽有餘,甚至許多機型只能支持到 7.5W 快充。
搭配的定製車充採用雙 USB-A 接口輸出,單口輸出功率可達 18W 、雙口同時輸出可達 36W ,能一次滿足車內駕駛和乘客兩位的同時充電需求。

▲圖片來源:ZMI 紫米

其他小細節部分, ZMI 無線充車載支架(自動版)夾臂內側採用矽膠墊能增添防滑、保護的作用。除了安裝在冷氣出風口的夾具固定,也標配黏貼底座以便一些希望能將支架黏貼固定在車內的族群。然而,這款車載支架還是能使用有線充電的,因為在支架採用 U 型開口,就是方便用戶使用充電線進行有線充電使用。

▲圖片來源:ZMI 紫米

南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

搬家費用:依消費者運送距離、搬運樓層、有無電梯、步行距離、特殊地形、超重物品等計價因素後,評估每車次單

消息來源:NCC

延伸閱讀:
小米 POCO 官方 Facebook 粉專成立、官網上線,即將以 POCO 品牌「重返」台灣市場

小米有品推出 Lydsto 手持吸塵打氣機,眾籌價約 860 元

您也許會喜歡:

【推爆】終身$0月租 打電話只要1元/分

立達合法徵信社-讓您安心的選擇

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

透過選單樣式的調整、圖片的縮放比例、文字的放大及段落的排版對應來給使用者最佳的瀏覽體驗,所以不用擔心有手機版網站兩個後台的問題,而視覺效果也是透過我們前端設計師優秀的空間比例設計,不會因為畫面變大變小而影響到整體視覺的美感。

一次FGC導致CPU飆高的排查過程_網頁設計公司

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

節能減碳愛地球是景泰電動車的理念,是創立景泰電動車行的初衷,滿意態度更是服務客戶的最高品質,我們的成長來自於你的推薦。

    今天測試團隊反饋說,服務A的響應很慢,我在想,測試環境也會慢?於是我自己用postman請求了一下接口,真的很慢,竟然要2s左右,正常就50ms左右的。

    於是去測試服務器看了一下,發現服務器負載很高,並且該服務A佔了很高的cpu。先用top命令,看了load average,發現都到了1.5左右(雙核cpu)了,並且有一個java進程(20798)佔用cpu一直很高,如下圖:

    於是,用命令jps -l看了一下java的20798,剛好就是服務A。

    究竟服務A在跑什麼,畢竟是測試環境。於是使用top -Hp 20798看一下是哪個線程在跑,如下圖:

    

    發現線程20840佔用cpu非常高,其他幾乎都是0。通過以下命令輸出該線程id(20840)的16進制:

printf "%x\n" 20840

  

輸出如下:

    線程id(20840)的16進制是5186。

    然後使用以下命令打印出該線程的堆棧信息:

jstack -l 20798 | grep -A 20 5168

  

    輸入如下:

    發現佔用cpu的進程是jvm的GC線程,於是猜測是不是由於一直在進行FGC導致cpu飆高,於是使用以下命令看下FGC的頻率和耗時:

jstat -gc 20798 1000

  

輸出如下:

    發現,果然是不斷地在進行着FGC,並且每次FGC的時間一直在升高。是什麼導致一直都在FGC呢?是有大對象一直在創建,回收不了?於是使用以下命令看下heap中的對象情況:

jmap -histo:live 20798 | head -20

  

輸出如下:

    發現一個業務類對象竟然有150w+個,並且佔用了264M的堆大小,什麼情況,並且這150w+個對象還是存活的(注意jmap使用的時候,已經帶上了:live選項,只輸出存活的對象),嚇我一跳。於是趕緊使用以下命令打出線程堆棧來看一下:

jstack -l 20798 > jstack_tmp.txt

  

南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

搬家費用:依消費者運送距離、搬運樓層、有無電梯、步行距離、特殊地形、超重物品等計價因素後,評估每車次單

輸出如下:

然後使用如下命令在輸出的線程堆棧中根據對象類查找一下:

grep -C 30 'omments' jstack_tmp.txt

  

輸出如下:

    猜測是由於一下次從db load出了太多的CommentsEntity。

    於是使用以下命令dump出heapdump出來重複確認一下:

jmap -dump:live,format=b,file=news_busy_live.hprof 20798

  

    把heapdump文件news_busy_live.hprof下載到windows本地,使用mat工具進行分析,第一次打開發現打不開,畢竟news_busy_live.hprof有3G那麼大,mat直接報OOM打不開,發現mat的配置文件MemoryAnalyzer.ini裏面的配置-Xmx1024m,heap size才1G,太小了,於是改成-Xmx4096m,保存,重新打開mat,再打開news_busy_live.hprof文件即可,如下圖:

    發現mat已經幫我們分析出了內存泄漏的可以對象,233w+個對象(前面通過jmap命令輸出的150W+個,是後面為了寫文章而專門重現的操作,這裏的233w+個是當時真的出問題的時候dump出來的heap dump文件),太恐怖了。

    通過以下操作,查看

點擊exclude all ….,因為弱引用,軟引用,虛引用等都可以被GC回收的,所以exclude,輸出如下:

    發現一共有6個線程引用了那233w+個對象,於是去前面dump出來的線程堆棧跟蹤以下這幾個線程的情況,發現堆棧裏面剛好這幾個線程也是在處理comments相關的邏輯,這個是剛好碰巧,一般線程id都對不上的,畢竟線程處理完之後就釋放了的。所以我們還是看回前麵線程堆棧的信息,這裏貼出根據關鍵字”omment”搜索出來的線程堆棧的信息,如下:

"XNIO-5 task-77" #248 prio=5 os_prio=0 tid=0x00007fc4511be800 nid=0x8f7 runnable [0x00007fc3e5af2000]   java.lang.Thread.State: RUNNABLE       ...        at cn.xxxxxx.news.commons.redis.RedisUtil.setZSet(RedisUtil.java:1080)        at cn.xxxxxx.news.service.impl.CommentsServiceV2Impl.setCommentIntoRedis(CommentsServiceV2Impl.java:1605)        at cn.xxxxxx.news.service.impl.CommentsServiceV2Impl.loadCommentsFromDB(CommentsServiceV2Impl.java:386)        ...        at cn.xxxxxx.xxxs.controller.vxxx.xxxxController.getxxxxxx(NewsContentController.java:404)        at cn.xxxxxx.xxx.controller.vxxx.xxxxxController$$FastClassBySpringCGLIB$$e7968481.invoke(<generated>)        ...        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)        at java.lang.Thread.run(Thread.java:745)​   Locked ownable synchronizers:        - <0x00000000f671ecd0> (a java.util.concurrent.ThreadPoolExecutor$Worker)​

  

    

    從上面的堆棧信息,結合前面的猜測(猜測是一次性從db load出太多的CommentsEntity),猜測應該是函數loadCommentsFromDB一次性從db load出太多CommentsEntity了。於是看了一下業務代碼,發現load出來的commentsEntity會放到redis的某一個zset,於是使用redis destopmanger看一下這個zset的數據,發現這個zset有22w的數據,從中找出幾條,發現對應的newsPk都是同一個,根據newsPk在db中找一下該newsPk的comments總記錄,發現該newsPk的comments記錄數是38w+條,那就是這個問題了,一次性從db中load了38w+的數據到內存。

    一次性load那麼多數據到內存,這肯定是一個慢查詢,不管是db還是網絡io,都肯定很慢。然後發現業務代碼還會有一個for循環,把這個CommentsEntityList遍歷一遍,一條一條放到redis,這也是一個非常慢的過程。

    然後我去看了服務A的access log,發現在短時間內,請求了該newsPk多次數據,所以就導致了jvm的heap空間不夠,然後出現不斷FGC的現象,並且該newsPk的請求,由於超時,都在網關超時返回了。

    為了驗證這個問題,我把相關的redis緩存刪除,然後調用該newsPk的接口獲取數據,發現很慢,並且cpu立刻飈上去了,然後調多幾次,並且不斷地進行FGC,至此已經復現了該問題,和猜測的一樣。等數據load到redis之後,再訪問該接口,就很正常沒問題。

    上面發現問題的代碼,找時間做一下優化才行,先重啟服務A,讓服務可用先。

 

                    歡迎關注微信公眾號“ismallboy”,請掃碼並關注以下公眾號,並在公眾號下面回復“FGC”,獲得本文最新內容。

                                                           

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

透過選單樣式的調整、圖片的縮放比例、文字的放大及段落的排版對應來給使用者最佳的瀏覽體驗,所以不用擔心有手機版網站兩個後台的問題,而視覺效果也是透過我們前端設計師優秀的空間比例設計,不會因為畫面變大變小而影響到整體視覺的美感。