主頁 > 後端開發 > InnoDB學習(一)之BufferPool

InnoDB學習(一)之BufferPool

2021-12-07 15:17:04 後端開發

我們知道InnoDB資料庫的資料是持久化在磁盤上的,而磁盤的IO速度很慢,如果每次資料庫訪問都直接訪問磁盤,顯然嚴重影響資料庫的性能,為了提升資料庫的訪問性能,InnoDB為資料庫的資料增加了記憶體快取區(BufferPool),避免每次訪問資料庫都進行磁盤IO,

快取區BufferPool

快取區并不是Innodb中特有的概念,作業系統中也有快取區的概念,當用戶第一次從磁盤讀取檔案時,會把檔案快取到記憶體中,后續再對這個檔案進行讀操作就可以直接從記憶體中讀,從而減少磁盤IO次數,快取只是記憶體中的一塊連續空間,InnoDB是如何合理利用快取區的空間的呢?本文會從以下幾個方面介紹InnoDB的快取區:

  1. 快取區概覽:InnoDB快取區的結構和狀態查詢;
  2. 快取區實體(BufferPool Instance):快取區可以劃分為多個實體;
  3. BufferChunk:快取區實體內的資料塊;
  4. 控制塊和資料頁:InnoDB是以什么形式快取資料庫中的資料的;
  5. 空閑空間管理;快取區內的空閑空間管理邏輯;
  6. 用戶資料管理:資料庫資料和索引在快取區快取的管理;
  7. 自適應哈希索引:優化熱點資料等值查詢的哈希索引;
  8. ChangeBuffer簡介:提高資料庫更新效率的ChangeBuffer;
  9. 鎖資訊管理:InnoDB中的行鎖資訊也是存放在快取區中的;

快取區概覽

InnoDB中的快取區叫innodb_buffer_pool,當讀取資料時,就會先從快取中查看是否資料的頁(page)存在,不存在的話去磁盤上檢索,查到后快取到innodb_buffer_pool中,同理,插入、修改、洗掉也是先操作快取里資料,之后再以一定頻率更新到磁盤上,這個刷盤機制叫做Checkpoint,

如下圖所示,InnoDB中的資料主要有資料頁、索引頁、插入快取、自適應哈希索引、鎖資訊和資料字典資訊,我們經常聽到的RedoLog不在快取區中,

InnoDB快取區結構

MySQL默認的innodb_buffer_pool的大小是128M,我們可以通過以下命令查看innodb_buffer_pool的引數,執行結果如下圖所示:

show variables like 'innodb_buffer_pool%';

InnoDB快取區引數示例

在MySQL使用程序中,我們可能需要查看快取區的狀態,比如已使用空間大小、臟頁大小等狀態,我們可以通過以下命令查看innodb_buffer_pool的狀態,執行結果如下圖所示,圖中的執行結果中,共有8192頁資料,

show global status like '%innodb_buffer_pool%';

InnoDB快取區狀態示例

快取區實體

快取區本身是一塊記憶體空間,在多執行緒并發訪問快取的情況下,為了保證快取頁資料的正確性,可能會對快取區單實體鎖互斥訪問,如果快取區非常大并且多執行緒并發訪問非常高的情況下,單實體快取區的可能會影響請求的處理速度,如下圖所示,資料庫快取區大小為3G,并發訪問QPS為3000,如果快取區只有一個實體,那么這3000個請求可能需要競爭同一個互斥鎖,

InnoDB快取區單個實體

MySQL 5.5引入了快取區實體作為減小內部鎖爭用來提高MySQL吞吐量的手段,用戶可以通過設定innodb_buffer_pool_instances引數來指定InnoDB快取區實體的數目,默認快取區實體的數目為1,快取區實體的大小均為`innodb_buffer_pool_size/innodb_buffer_pool_instances,如下圖所示,資料庫快取區大小為3G,并發訪問QPS為3000,如果快取區有3個實體,理想情況下最多每1000個請求會競爭同一個互斥鎖,

InnoDB快取區多個實體

如果快取區總空間大小小于1G,innodb_buffer_pool_instances會被重置為1,因為小空間的多個快取區實體反而會影響查詢性能,

快取區實體有以下特點:

  1. 快取區實體有自己的鎖/信號量/物理塊/邏輯鏈表,快取區實體之間沒有鎖競爭關系;
  2. 所有快取區實體的空間在資料庫啟動時分配,資料庫關閉后釋放;
  3. 快取頁按照哈希函式隨機分布到不同的快取實體中;

快取區實體的BufferChunk

我們知道快取區可以包含多個快取區實體,每個快取區實體包含一塊連續的記憶體空間,InnoDB把這塊空間劃分為多個BufferChunk,BufferChunk是InnoDB中的底層的物理塊,BufferChunck中包含資料頁和控制塊兩部分,

InnoDB快取區引數示例

BufferChunk是最低層的物理塊,在啟動階段從作業系統申請,直到資料庫關閉才釋放,通過遍歷chunks可以訪問幾乎所有的資料頁,有兩種狀態的資料頁除外:

  1. 沒有被解壓的壓縮頁(BUF_BLOCK_ZIP_PAGE);
  2. 修改過且解壓頁已經被驅逐的壓縮頁(BUF_BLOCK_ZIP_DIRTY);

BufferChunck中包含資料頁和控制塊兩部分,二者存放的資料如下:

  1. 控制塊:頁面管理資訊/互斥鎖/頁面的狀態等資料塊控制資訊;
  2. 資料頁:資料庫資料/鎖資料/自適應哈希資料,資料頁的大小默認為16K;

BufferChunck資料塊的大小是可配置的,MySQL配置中默認BufferChunck資料塊大小如下所示,用戶可以在MySQL實體啟動之前通過修改組態檔或啟動引數中指定,達到自定義BufferChunck資料塊的大小的目的,

$> mysqld --innodb-buffer-pool-chunk-size=134217728
[mysqld]
innodb_buffer_pool_chunk_size = 134217728

用戶自定義innodb_buffer_pool_chunk_size引數的大小應當小于單個快取區實體的空間大小,如果innodb_buffer_pool_chunk_size值乘以innodb_buffer_pool_instances大于初始化緩沖池總大小時, innodb_buffer_pool_chunk_size則截斷為innodb_buffer_pool_size/innodb_buffer_pool_instances,

控制塊和資料頁

通過上文,我們知道InnoDB中的底層物理塊是BufferChunk,BufferChunk中包含了控制塊和資料頁,本節會介紹資料頁和控制塊分別包含哪些資料,

控制塊

InnoDB中的每個資料頁都有一個相對應的控制塊,用于存盤資料頁的管理資訊,但是這些資訊不需要記錄到磁盤,而是根據讀入資料塊在記憶體中的狀態動態生成的,查找或者修改資料頁時,總是會通過控制塊進行資料塊操作,控制塊主要包含以下資料:

  1. 頁面管理的普通資訊/互斥鎖/頁面的狀態等;
  2. 空閑鏈表/LRU鏈表/FLU鏈表等鏈表的管理;
  3. 按照一定的哈希函式快速定位資料頁位置;

InnoDB快取區控制塊

資料頁

InnoDB中,資料管理的最小單位為頁,默認是16KB,頁中除了存盤用戶資料,還可以存盤控制資訊的資料,InnoDB IO子系統的讀寫最小單位也是頁,如果對表進行了壓縮,則對應的資料頁稱為壓縮頁,如果需要從壓縮頁中讀取資料,則壓縮頁需要先解壓,形成解壓頁,解壓頁為16KB,壓縮頁的大小是在建表的時候指定,目前支持16K,8K,4K,2K,1K,即使壓縮頁大小設為16K,在blob/varchar/text的型別中也有一定好處,假設指定的壓縮頁大小為4K,如果有個資料頁無法被壓縮到4K以下,則需要做B-tree分裂操作,這是一個比較耗時的操作,

資料頁可以用于存放以下型別的資料,下文中我們會對這些型別的資料結構進行詳細介紹:

  • 用戶資料,聚簇索引和非聚簇索引對應的節點資料;
  • 行鎖資訊,InnoDB鎖過多例外時,可以通過增加BufferPool大小解決;
  • 自適應哈希,用于快取熱點資料;
  • ChangeBuffer快取;

空閑空間管理

當我們最初啟動服務器的時候,需要完成對的初始化程序,就是分配的記憶體空間,把它劃分成若干對控制塊和快取頁,但是此時并沒有真實的磁盤頁被快取到中(因為還沒有用到),之后隨著程式的運行,會不斷的有磁盤上的頁被快取到中,那么問題來了,從磁盤上讀取一個頁到中的時候該放到哪個快取頁的位置呢?或者說怎么區分中哪些快取頁是空閑的,哪些已經被使用了呢?我們最好在某個地方記錄一下哪些頁是可用的,我們可以把所有空閑的頁包裝成一個節點組成一個雙向鏈表,這個鏈表也可以被稱作(或者說空閑鏈表),

如果InnoDB剛剛啟動,快取區的所有快取頁都是空閑的,每一個快取頁都會被加入到空閑鏈表中,此時空閑串列的結構如下所示(此處省略資料頁,空閑鏈表的指標指向資料塊的控制塊),

InnoDB快取區空閑空間

在需要加載快取頁到BufferPool的情況下,如果空閑鏈表不為空,我們可以從空閑鏈表中獲取一頁空閑資料頁,將快取放入空閑的資料頁,以LRU(后文詳細介紹)為例,InnoDB啟動后,LRU加載第一個快取頁之后,BufferPool中的資料情況如下所示,

InnoDB快取區空閑空間使用

用戶資料管理

用戶資料管理是BufferPool中最重要的資料,包含表資料與索引資料等資料,用戶資料會按照資料的狀態進行管理,主要包含以下資料管理,下文會一一介紹這幾種鏈表:

  1. 最近最少使用鏈表(Least Recently Used, LRU):InnoDB中最重要的鏈表,包含所有讀取進來的資料頁;
  2. 臟頁鏈表(Flush LRU List):管理LRU中的臟頁,后臺執行緒定時寫入磁盤;
  3. 解壓頁鏈表(Unzip LRU List):管理LRU中的解壓頁資料,解壓頁資料是從壓縮頁通過解壓而來的;
  4. 壓縮頁鏈表(Zip List):顧名思義,對頁資料壓縮后組成的鏈表;

最近最少使用鏈表LRU

最近最少使用鏈表LRU用于快取表資料與索引資料,由于記憶體大小通常遠遠小于磁盤大小,記憶體中無法快取全部的資料庫資料,所以快取通常需要一定的淘汰策略,淘汰快取中不經常使用的資料頁,InnoDB的BufferPool采用了改進版的LRU的淘汰策略,

如下圖所示,LRU鏈表的結構和空閑鏈表的結構類似,是一個雙向鏈表,鏈表中的節點包含指向資料頁控制塊的指標,可以通過控制塊訪問資料頁中的資料,

InnoDB快取區LRU鏈表

當需要將新資料頁添加到緩沖池時,最近最少使用的資料頁會可能會從LRU鏈表中淘汰,并將新資料頁添加到LRU鏈表的中間,此插入點將列LRU鏈表劃分為兩個子鏈表:

  1. 頭部的5/8區域,最近訪問多的熱資料串列;
  2. 尾部的3/8區域,最近訪問少的冷資料串列;

InnoDB快取區LRU鏈表

LRU演算法會將經常使用的資料頁保留在熱資料串列中,冷資料串列中包含了不經常訪問的資料頁,這些資料頁是LRU串列滿了之后最先被淘汰的資料,默認情況下,演算法的流程如下:

  1. LRU鏈表的的后3/8區域用于存盤冷資料;
  2. LRU鏈表的中點是熱資料尾部與冷資料頭部相交的邊界;
  3. 被訪問的冷資料會從冷資料鏈表移動到熱資料鏈表;
  4. 熱資料鏈表中的資料如果長時間不訪問,會逐漸移入冷資料鏈表;
  5. 冷資料長時間不被訪問,并且LRU鏈表滿了,那么末尾的冷資料會淘汰出LRU鏈表;
  6. 預讀的資料只會插入LRU鏈表,不會被移動到熱資料鏈表;

LRU演算法還有一個問題,當某一個SQL陳述句,要批量掃描大量資料時,由于這些頁都會被訪問,可能導致把緩沖池的所有頁都替換出去,導致大量熱資料被換出,MySQL性能急劇下降,這種情況叫緩沖池污染,MySQL緩沖池加入了一個冷資料停留時間視窗的機制:

  1. 假設T=冷資料停留時間視窗;
  2. 插入冷資料頭部的資料頁,即使立刻被訪問,也不會立刻放入新生代頭部;
  3. 只有滿足被訪問并且在冷資料區域停留時間大于T,才會被放入新生代頭部;

加入冷資料停留時間視窗策略后,短時間內被大量加載的頁,并不會立刻插入新生代頭部,而是優先淘汰那些短期內僅僅訪問了一次的頁,

MySQL中LRU鏈表相關的引數:

  • innodb_old_blocks_pct:冷資料占整個LRU鏈長度的比例,默認是3/8,即整個LRU中熱資料與冷資料長度比例是5:3,
  • innodb_old_blocks_time冷資料停留時間視窗機制中冷資料停留時長;

臟資料鏈表FLU

當需要更新一個資料頁時,如果資料頁在記憶體中就直接更新更新記憶體中的資料,但是由于寫回磁盤的代價比較高,所以InnoDB并不會立刻把修改后的資料寫回磁盤,此時,就出現了快取區資料頁和磁盤資料頁中的資料不一致的情況,這種情況下快取區資料頁被稱為臟頁,管理所有臟頁的鏈表叫臟資料鏈表,以下為臟資料鏈表的示例圖:

InnoDB快取區LRU鏈表

臟資料鏈表是LRU鏈表的子集,LRU鏈表包含了所有的臟頁資料,臟頁中的資料最終是要寫回磁盤的,將記憶體資料頁刷到磁盤的操作稱為刷臟,以下是幾種會觸發InnoDB刷臟的情況

  • InnoDB的RedoLog寫滿了,這時候系統會停止所有更新操作,把Checkpoint往前推進,RedoLog留出空間可以繼續寫;
  • 當系統記憶體不足,需要把一個臟頁要從LRU鏈表中淘汰時,要先把臟頁寫回磁盤;
  • MySQL在空閑時,會自動把一部分臟頁寫回磁盤;
  • MySQL正常關閉時,會把所有臟頁都寫回磁盤;

InnoDB中可以通過一些引數設定刷臟行為:

  • innodb_io_capacity:MySQL資料檔案所在磁盤的IO能力,innodb_io_capacity引數會影響MySQL刷臟頁的速度,磁盤的IOPS可以通過FIO工具來測驗,測驗命令如下所示:

    fio -filename=$filename -direct=1 -iodepth 1 -thread -rw=randrw -ioengine=psync -bs=16k -size=500M -numjobs=10 -runtime=10 -group_reporting -name=mytest
    

    如果不能正確地設定innodb_io_capacity引數,可能能導致資料庫性能問題,舉個例子說明:如果MySQL主機磁盤用的是SSD,但是innodb_io_capacity的值設定的是比較低,只有300,這種情況下,InnoDB認為這個系統的IO能力只有300,所以刷臟頁刷得特別慢,甚至比臟頁生成的速度還慢,這樣就造成了臟頁累積,影響了查詢和更新性能,

  • innodb_flush_neighbors:在準備刷一個臟頁的時候,如果這個資料頁旁邊的資料頁剛好是臟頁,就會把這個“鄰居”也帶著一起刷掉;而且這個把“鄰居”拖下水的邏輯還可以繼續蔓延,也就是對于每個鄰居資料頁,如果跟它相鄰的資料頁也還是臟頁的話,也會被放到一起刷,innodb_flush_neighbors引數就是用來控制這個行為的,值為1的時候會有上述的“連坐”機制,值為0時表示不找鄰居,自己刷自己的,對于SSD這類IOPS比較高的設備,IOPS往往不是瓶頸,innodb_flush_neighbors應該設定為0,在MySQL8.0中,innodb_flush_neighbors引數的默認值已經是0了,

  • innodb_max_dirty_pages_pct:臟頁比例超過innodb_max_dirty_pages_pct之后,InnoDB會全力刷臟頁,如果沒超過這個比例,那么刷臟頁速度=max(當前臟頁比例/innodb_max_dirty_pages_pct*innodb_io_capacity, RedoLog的快取大小計算刷臟頁速度);

壓縮頁鏈表(Zip List)

Mysql允許用戶對表進行壓縮以節省磁盤空間,這些壓縮頁的資料在進入記憶體之后,要進行解壓之后才能使用,

我們可以通過以下SQL陳述句建立一張InnoDB資料表:

create table user_info
(
    id   int primary key,
    age  int not null,
    name varchar(16),
    sex  bool
)engine=InnoDB;

對于建立好的InnoDB資料表,我們可以通過以下SQL陳述句對表進行壓縮,壓縮后表占用的磁盤空間會減小:

alter table user_info row_format=compressed;

InnoDB中的表壓縮是針對表資料頁的壓縮,不僅可以壓縮表資料,還可以壓縮表索引,壓縮頁的大小可以是1k/2k/4k/8k,

壓縮頁鏈表存盤的就是這些壓縮后的頁,壓縮頁在加載進記憶體之后,并不會立即解壓,而是在需要使用的時候再進行解壓,

壓縮頁有不同的大小1k/2k/4k/8k,InnoDB使用了伙伴管理演算法來管理壓縮頁,有5個ZipFree鏈表分別管理1k/2k/4k/8k/16K的記憶體碎片,8K的鏈表里存盤的都是8K的碎片,如果新讀入一個8K的頁面,首先從這個鏈表中查找,如果有則直接回傳,如果沒有則從16K的鏈表中分裂出兩個8K的塊,一個被使用,另外一個放入8K鏈表中,

解壓頁鏈表(Unzip LRU List)

壓縮頁鏈表中的資料都是被壓縮的,不能直接CRUD,使用前需要解壓,解壓后的資料都存盤在解壓頁鏈表中,解壓頁鏈表中的資料寫回磁盤時需要壓縮,

自適應哈希索引

我們知道B+樹默認的索引資料結構是B+樹,B+樹對范圍查詢或者LIKE語法的支持比較好,

如果資料庫中有大量的等值查詢,使用哈希索引能顯著提升查詢效率,Innodb存盤引擎會監控對表上二級索引的查找,如果發現某二級索引被頻繁訪問,二級索引成為熱資料,會對該熱點資料建立記憶體哈希索引,這個索引被稱為自適應哈希索引,

自適應哈希索引默認是開啟狀態,可以通過設定innodb_adaptive_hash_index變數或在啟動MySQL時添加--skip-innodb-adaptive-hash-index變數啟用自適應哈希索引,

InnoDB中可以查看到哈希索引的使用情況,命令及輸出如下所示:

mysql> show engine innodb status\G
……
Hash table size 34673, node heap has 0 buffer(s)
0.00 hash searches/s, 0.00 non-hash searches/s

ChangeBuffer

在修改資料庫資料時,如果對應的資料頁剛剛好在快取區,可以之間修改快取區的資料頁,并把資料頁標記為臟頁,

如果修改資料資料時,對應的資料頁如果不在快取區,就需要把資料頁從磁盤加載到快取區,然后進行修改,對于寫多讀少的場景,會產生大量的磁盤IO,影響資料庫的性能,

Change Buffer對資料更新程序有加速作用, 如果資料頁沒有在記憶體中,會將更新操作快取到Change Buffer 中,這樣就不需要從磁盤讀入這個資料頁,減少了IO操作,提高了性能, 先將更新操作,記錄在Change Buffer 中,之后再進行 merge,真正進行資料更新,InnoDB Change Buffer比較復雜,我會在后續單獨章節中進行介紹,

InnoDB Change Buffer

行鎖資訊管理

InnoDB支持行鎖,可以對資料庫中的資料進行加鎖操作,這些鎖資訊也存放在BufferPool中,具體存盤格式此處不做詳細解釋,

既然鎖資訊都存放在BufferPool中,那么鎖的數目肯定受快取區大小的影響,如果InnoDB中鎖占據的空間超過了BufferPool總大小的70%,在新添加鎖時會報以下錯誤:

[FATAL] InnoDB: Over 95 percent of the buffer pool is occupied by lock heaps or the adaptive hash index! Check that your transactions do not set too many row locks. Your buffer pool size is 8 MB. Maybe you should make the buffer pool bigger? We intentionally generate a seg fault to print a stack trace on Linux!For more information, see Help and Support Center at http://www.mysql.com.

我是御狐神,歡迎大家關注我的微信公眾號:wzm2zsd

qrcode_for_gh_83670e17bbd7_344-2021-09-04-10-55-16

參考檔案

  1. MySQL 8.0 Reference Manual/The InnoDB Storage Engine/InnoDB Architecture
  2. Chunk Change: InnoDB Buffer Pool Resizing
  3. 玩轉MySQL之十InnoDB Buffer Pool詳解
  4. InnoDB的Buffer Pool簡介
  5. Mysql的Innodb存盤引擎緩沖池個人理解
  6. InnoDB關鍵特性之自適應hash索引
  7. InnoDB頁壓縮技術

本文最先發布至微信公眾號,著作權所有,禁止轉載!

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/375118.html

標籤:Java

上一篇:MQ之RocketMQ專業術語

下一篇:Flowable - 6.6.0 更新說明 (主流作業流引擎)

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more