主頁 > 後端開發 > JDK之ZGC介紹

JDK之ZGC介紹

2020-12-23 13:25:14 後端開發

**視頻課:https://edu.csdn.net/course/detail/31331
前言

ZGC是最近由Oracle為OpenJDK開源的新垃圾收集器,它主要由Per Liden撰寫,ZGC類似于Shenandoah或Azul的C4,專注于減少暫停時間的同時仍然壓縮堆 ,

雖然我不會在這里給出完整的介紹,但“壓縮堆”只是意味著將仍然存活的物件移動到堆的其他區域.這樣做有助于減少碎片,但通常這也意味著整個應用程式(包括其所有執行緒)需要暫停,這通常被稱為Stop the world ,只有GC完成后,才能恢復應用程式,

在GC相關的文獻中,應用程式通常稱為mutator ,因為從GC的角度來看,應用程式會改變堆(mutates the heap),根據堆的大小,這樣的暫停可能需要幾秒鐘,這對于互動式應用程式來說可能是難以接受的,

有幾種方法可以減少暫停時間:

GC可以在壓縮時使用多個執行緒(并行壓縮 parallel compaction)
壓縮作業也可以分為多個暫停(增量壓縮 incremental compaction)
壓縮堆的同時不暫停應用程式,或者只是很短時間暫停(并發壓縮 concurrent compaction)
Go的GC就是完全不壓縮堆

如前所述,ZGC會進行并發壓縮,這當然不是一個簡單的實作功能,因此我想描述一下這是如何作業的,為什么這很復雜?

你需要將物件復制到另一個記憶體地址,同時另一個執行緒仍然可以讀寫舊物件,

如果物件已經復制成功,那么堆中仍有許多指向舊地址的參考需要更新到新地址,

雖然并發壓縮(concurrent compaction)似乎是上述方案中降低暫停時間的最佳解決方案,但肯定會涉及一些權衡,因此,如果您不關心暫停時間,那么最好使用專注于吞吐量的GC,
GC屏障 (GC Barriers)

理解ZGC如何進行并發壓縮的關鍵是Load barrier (通常在GC文獻中稱為Read barrier).這里簡單介紹一下,詳細的描述請看下面的Load Barrier一節,

如果GC有讀取屏障(Load barrier),則在從堆讀取參考時,GC需要執行一些額外操作,在Java中,也就是像執行這樣的代碼Object xxx=obj.field時需要額外操作,

對于像obj.field = value這樣的操作,GC也可能需要寫入屏障(叫做Write Barrier或者Store Barrier)[譯注:在分代GC還有參考計數中會用到寫入屏障].

這兩個操作都比較特殊因為它們在每次讀取或寫入堆時發生的,Load Barrier和Store Barrier的名稱有點令人困惑,但注意這個屏障與CPU的記憶體障礙是完全不同的兩個概念

堆中的讀取和寫入都非常常見,因此兩種GC屏障都需要非常高效,在常見情況下就是一些匯編代碼,Read barrier通常比Write Barrier大一個數量級(可能會因應用程式而異),因此Read Barrier對性能要求更高,

例如,分代GC通常只需要一個寫屏障,不需要讀屏障,ZGC則需要一個讀屏障但沒有寫屏障,對于并發壓縮,我沒有看到沒有讀取障礙的解決方案,

這里需要注意:即使GC需要某種型別的屏障,只有在讀取或寫入堆中的參考時需要它們,讀取或寫入像int或double這樣的基本型別是不需要屏障的.
指標標記(Pointer tagging Or Colored Pointers )

ZGC在堆參考中存盤額外的元資料 ,在x64上是64 bit(ZGC目前不支持compressed oops和 class pointers),64位中的48位用做x64上的虛擬記憶體地址 ,雖然確切地說只有47位,因為第47位確定了位48-63的值(目前這些位都是0),ZGC保留物件實際地址的前42位(在源代碼中稱為偏移量 ),42位地址理論上就會有4TB的堆大小限制,其余的位用于這些標志: finalizable , remapped , marked1和marked0 (保留一位用于將來使用),如下圖所示:

6 4 4 4 4 4 0
3 7 6 5 2 1 0
±------------------±±—±----------------------------------------------+
|00000000 00000000 0|0|1111|11 11111111 11111111 11111111 11111111 11111111|
±------------------±±—±----------------------------------------------+
| | | |
| | | * 41-0 Object Offset (42-bits, 4TB address space)
| | |
| | * 45-42 Metadata Bits (4-bits) 0001 = Marked0
| | 0010 = Marked1
| | 0100 = Remapped
| | 1000 = Finalizable
| |
| * 46-46 Unused (1-bit, always zero)
|

  • 63-47 Fixed (17-bits, always zero)

在堆參考中具有元資料資訊使得解參考更加昂貴,因為需要mask地址以獲得沒有元資訊的真實地址,ZGC采用了一個很好的技巧來避免這種情況:

當從記憶體中讀取時,會設定marked0 , marked1或remapped中的一個,

在偏移x處分配頁面(allocating a page)時,ZGC將同一頁面映射到3個不同的地址 :

for marked0 :(0b0001 << 42) | x
for marked1 : (0b0010 << 42) | x
for remapped : (0b0100 << 42) | x

因此,ZGC從地址4TB開始保留16TB的地址空間(但實際上并未使用所有這些記憶體),如下圖:

±-------------------------------+ 0x0000140000000000 (20TB)
| Remapped View |
±-------------------------------+ 0x0000100000000000 (16TB)
| (Reserved, but unused) |
±-------------------------------+ 0x00000c0000000000 (12TB)
| Marked1 View |
±-------------------------------+ 0x0000080000000000 (8TB)
| Marked0 View |
±-------------------------------+ 0x0000040000000000 (4TB)

在任何時間點,只使用這三個視圖中的一個,除錯時可以取消映射(unmapped)未使用的視圖來驗證正確性,
Pages & Physical & Virtual Memory

Shenandoah將堆分成大量同樣大小的區域 ,除了不適合單個區域的大物件外,物件通常不會跨越多個區域,大物件被分配在多個連續區域中,我非常喜歡這種方法,因為它非常簡單,

在這方面,ZGC與Shenandoah非常相似,在ZGC的說法中,區域稱為頁面Pages ,

與Shenandoah的主要區別:ZGC中的頁面可以有不同的大小(但在x64上總是2MB的倍數),

ZGC有3種不同的頁面型別: 小型 (2MB大小), 中型 (32MB大小)和大型 (2MB的倍數),

在小頁面中分配小物件(最大256KB大小),在中型頁面中分配中型物件(最多4MB),大頁面中分配大于4MB的物件,大頁面只能存盤一個物件.小頁面或中間頁面可以分配多個,

有些令人困惑的是大頁面實際上可能小于中等頁面(例如,對于大小為6MB的大物件),

ZGC的另一個不錯的特性是,它還可以區分物理記憶體和虛擬記憶體,這背后的想法是通常有足夠的虛擬記憶體(ZGC總是4TB),而物理記憶體更稀缺,物理記憶體可以擴展到最大堆大小(使用-Xmx設定),因此這比4 TB的虛擬記憶體要小得多,在ZGC中分配特定大小的頁面意味著分配物理和虛擬記憶體,在ZGC中,物理記憶體不需要是連續的,虛擬記憶體空間是連續的,

為什么說這是一個不錯的屬性?

分配連續范圍的虛擬記憶體是很容易的,因為我們通常有足夠的虛擬記憶體,但在物理記憶體中有3個大小為2MB的空閑頁面的情況很普通,但是對于大型物件分配我們需要6MB的連續記憶體,有足夠的空閑物理記憶體,但不幸的是這個記憶體是不連續的,ZGC能夠將這些非連續的物理頁面映射到單個連續的虛擬記憶體空間,如果無法映射,我們就會耗盡記憶體(發生OOM)
標記和重新安置物件(Marking & Relocating objects)

垃圾回收主要分為兩個階段:標記和重新安置(實際上不止這兩個階段,你可以查閱原始碼),

[譯注:重新安置(Relocating)指的是把物件從一個記憶體區域移到另外一個區域,重映射(Remapping)只的是把指向老的地址的參考更新到新的地址]

一次GC從標記階段開始,標記所有可到達的物件,在這個階段結束時,我們知道哪些物件仍然存活,哪些物件是垃圾,ZGC將此資訊存盤在每個頁面的Live Map中,Live Map是一個位圖(bitmap) ,用于存盤給定索引處的物件是否可達和/或最終可達(對于具有finalize method的物件而言),

在標記階段,應用程式執行緒中的load-barrier將未標記的參考推送到執行緒區域標記緩沖區,只要此緩沖區已滿,GC執行緒就可以獲得此緩沖區的所有權,并以遞回方式遍歷此緩沖區中的所有可到達物件,在應用程式執行緒中標記只是將參考推送到緩沖區,GC執行緒負責遍歷物件圖并更新Live map.

標記階段結束后,ZGC要重新安置 Relocation set中的所有活動物件,

Relocation Set表示一組需要被回收的頁面(Pages),例如那些垃圾最多的頁面,存活的物件由GC執行緒或應用程式執行緒通過讀取屏障(Load Barrier)重新安置(relocated)(也就是放到新的地址去).ZGC為Relocation set中的每個頁面分配Forwarding table.

Forwarding table基本上是一個hash map,它存盤一個物件已被重新安置到的地址(如果該物件已經被重新安置),

ZGC方法的優點是我們只需要為relocation set中的頁面分配forwarding table的空間.
相比之下,Shenandoah將轉發指標存盤在每個物件本身,這樣就誰有一些額外的記憶體開銷,

GC執行緒遍歷 Relocation set中的存活物件,并重新安置(relocate)尚未重新安置的物件,這時可能發生應用程式執行緒和GC執行緒同時重新安置(relocate)同一個物件,在這種情況下,誰先relocate誰獲勝,ZGC使用原子CAS操作來確定勝者,

當不處于marking階段時,load-barrier會重新安置(relocates )/重新映射(remaps )從堆加載的所有參考,這確保了mutator看到的每個新參考都已指向物件的最新副本,重新映射(remaps)物件就是在forwarding table中查找新的物件地址,

一旦GC執行緒完成了relocation set的處理,重新安置階段就完成了,雖然這意味著所有物件都已重新安置,但通常仍會有參考指向relocation set,需要將其重新映射(remapped )到新地址,這些參考會被Load-Barrier自我修復,如果對于這些參考的讀取發生的不夠快,(也就是這段時間內,應用程式沒有讀到這些指向relocation set的參考),這些參考會在下一次mark階段給修復,這意味著標記階段還需要檢查 forward table以重新映射(remap) (但不重新安置 ,所有物件之前階段都保證被重新安置)物件到它們的新地址,

這也解釋了為什么物件參考中有兩個標記位(marked0 和marked1 ),標記階段在標記的marked0和marked1位之間交替,在重新安置階段之后,仍可能存在未重定向(remapped)的參考,所以我們需要知道上一個gc周期的情況,如果新的標記階段使用相同的標記位,則Load-Barrier就知道該參考為已標記,

(譯注:這里看起來像是GC周期remap和mark可以重疊,實際上確實是重疊的,如圖所示:
gc phase
更詳細的資訊可以看這個Slide)
Load-Barrier

從堆中讀取參考時,ZGC需要一個所謂的load-barrier(也稱為read-barrier),每次Java程式訪問物件型別的欄位時,我們都需要插入此load-barrier,例如obj.field ,訪問某些其他原始型別的欄位不需要屏障,例如obj.anInt或obj.anDouble ,ZGC不需要obj.field = someValue存盤/寫入障礙,

根據GC當前所處的階段(存盤在全域變數ZGlobalPhase中 ),如果尚未標記或重新安置物件,則屏障會標記物件或重新安置它

全域變數ZAddressGoodMask和ZAddressBadMask
存盤對應的掩碼,該掩碼確定參考是否已被認為是好的(這意味著已經標記或重新映射/重新安置remapped/relocated)或者是否仍然需要一些操作,這些變數僅在標記開始階段和重新安置階段同時改變.ZGC源代碼中的這個表格可以很好地概述這些掩碼的狀態:

           GoodMask         BadMask          WeakGoodMask     WeakBadMask
           --------------------------------------------------------------

Marked0 001 110 101 010
Marked1 010 101 110 001
Remapped 100 011 100 011

屏障的匯編代碼可以在MacroAssembler for x64中看到,我只會為這個屏障顯示一些偽匯編代碼:

mov rax, [r10 + some_field_offset]
test rax, [address of ZAddressBadMask]
jnz load_barrier_mark_or_relocate

otherwise reference in rax is considered good

第一個匯編指令從堆讀取參考: r10存盤物件參考, some_field_offset是一些欄位偏移常量,加載的參考存盤在rax暫存器中,

然后針對當前的壞掩碼測驗該參考(這只是一個位與),此處不需要同步,因為ZAddressBadMask僅在STW時才更新,如果結果不為零,我們需要執行屏障,

屏障需要根據我們當前所處的GC階段標記或重新安置物件,在此操作之后, 他需要更新存盤在r10 + some_field_offset中的參考來指向新參考,這步操作是必要的,以便來該欄位的后續加載回傳正確的參考,

由于我們可能需要更新參考地址,因此我們需要使用兩個暫存器r10和rax作為加載的參考和物件地址,正確的參考也需要存盤到暫存器rax中 ,這樣在后面的執行程序中我們就已經加載了正確的參考,

由于每個參考都需要標記或重新安置,因此在開始標記或重新安置階段后,吞吐量可能會立即降低,當大多數參考被修復時,這應該會變得更快,
Stop-the-World 停頓

ZGC并沒有徹底擺脫STW,收集器在開始標記,結束標記和開始重新安置時需要暫停,但這種暫停通常很短,只有幾毫秒,

當開始標記時,ZGC遍歷所有執行緒堆疊以標記root set,root set是遍歷物件圖的開始的地方,root set通常由本地和全域變陣列成,但也包括其他內部VM結構(例如JNI句柄),

結束標記階段時需要再次暫停,在此暫停中,GC需要清空并遍歷所有執行緒區域標記緩沖區,由于GC可能會發現一個未標記的大型子圖,因此可能需要更長時間,ZGC試圖通過在1毫秒后停止標記階段的結束來避免這種情況,它回傳到并發標記階段,直到遍歷整個物件圖,然后可以再次開始結束標記階段

啟動重新安置階段會再次暫停應用程式,此階段與開始標記非常相似,不同之處在于此階段重新安置Root Set中的物件,
zgc是一款可拓展的低時延,為實作以下幾個目標而誕生的垃圾回收器:

停頓時間不超過10ms
停頓時間不會因堆變大而變長
堆大小范圍可支持幾G到幾T

再看一下zgc的標簽:

region-based (和G1一樣)
NUMA-aware
Concurrent
Compacting
Using load barriers(讓一個CPU處理單元中的記憶體狀態對其它處理單元可見的一項技術,java的volatile底層使用的就是load barrier)
Using colored pointers()

zgc介紹-by hotspot garbage collector team:https://archive.fosdem.org/2018/schedule/event/zgc/attachments/slides/2211/export/events/attachments/zgc/slides/2211/ZGC_FOSDEM_2018.pdf
一、zgc在jdk各個版本的changelog:

JDK 13 (Released September 2019)

Increased max heap size from 4TB to 16TB
Support for uncommitting unused memory (JEP 351)
Support for -XX:SoftMaxHeapSIze
Support for the Linux/AArch64 platform
Reduced Time-To-Safepoint

JDK 12 (Released March 2019)

Support for concurrent class unloading
Further pause time reductions

JDK 11 (Released September 2018)

Initial version of ZGC
Does not support class unloading (using -XX:+ClassUnloading has no effect)

二、ZGC相關VM Options

General GC Options ZGC Options ZGC Dianostic Options (-XX:+UnlockDianosticVMOptions)

-XX:MinHeapSize, -Xms

-XX:InitialHeapSize, -Xms

-XX:MaxHeapSize, -Xmx

-XX:SoftMaxHeapSize

-XX:SoftRefLRUPolicyMSPerMB

-XX:ZAllocationSpikeTolerance

-XX:ZCollectionInterval

-XX:ZFragmentationLimit

-XX:ZMarkStackSpaceLimit

-XX:ZPath

-XX:ZUncommit

-XX:ZUncommitDelay

-XX:ZProactive

-XX:ZStatisticsForceTrace

-XX:ZStatisticsInterval

-XX:ZVerifyForwarding

-XX:ZVerifyMarking

-XX:ZVerifyObjects

-XX:ZVerifyRoots

-XX:ZVerifyViews

1、激活ZGC

-XX:+UnlockExperimentalVMOptions -XX:+UseZGC

2、設定堆大小,堆

-Xmx

3、并發執行緒數,并發執行緒數太多會導致占用太多cpu時間分片,太少會導致回收速度跟不上垃圾生產速度,如果系統追求的是低時延,盡量不要讓系統超負荷作業,cpu使用率盡量控制在70%以下

-XX:ConcGCThreads=

4、return unused memery to os

這里指的是設定了xms和xmx且xmx>xms的情況,zgc默認會回傳未使用的記憶體給作業系統,對于記憶體水位是重要指標的系統,回傳未使用記憶體可以更好的觀察記憶體使用情況,但如果要禁用這個功能,可以使用:-XX:-ZUncommit ,但無論使用哪種策略,jvm不會uncommit unsed memery導致堆大小小于xms,這也意味著如果配置xms=xmx,該特性會被隱式禁用

5、Enable Large Pages

啟用方式:-XX:+UseLargePages

Large Pages在Linux稱為Huge Pages,配置zgc使用Huge Pages可以獲得更好的性能(吞吐量、延遲、啟動時間),并且基本沒有缺點,除了配置稍微復雜一點,配置Huge Pages大小,需要注意JVM除了堆以外其他需要使用到的記憶體也得算進去,具體配置方法如下,就不翻譯了:

6、 Enable Transparent Huge Page(THP)

一般不建議在對延時敏感的系統下使用,THP一個使管理Huge Pages自動化的抽象層,

7、Enable NUMA Support

zgc默認開啟NUMA支持,意味著在分配堆記憶體時,會盡量使用NUMA-local的記憶體(比跨die訪問快3倍),但當jvm發現程式使用的只是cpu的一個子集(限定使用),則會自動禁用該特性,一般不需要關注這個特性,如果需要指定,可以通過以下引數指定

-XX:+/-UseNUMA

8、Enable GC logging

tea_year CSDN認證博客專家 大司徒
主要研究方向為大資料、人工智能、JAVA、資料庫 、前端開發、產品研發,曾經服務過大型上市國企IT部門,軟體企業聯合創始人,喜歡軟體研發管理、技術營銷!

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

標籤:java

上一篇:「補課」進行時:設計模式(20)——解釋器模式

下一篇:C++20 標準正式發布,命名為 ISO/IEC 14882:2020。

標籤雲
其他(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