JVM對象創建與內存分配機制深度剖析

對象創建的主要流程

在這里插入圖片描述

  1. 類加載檢查
    在創建對象之前,JVM 首先會檢查該類是否已經加載、解析并初始化:
    如果沒有,則會通過類加載機制加載類元信息(Class Metadata)到方法區。
    這個過程包括:加載(load)、驗證(verify)、準備(prepare)、解析(resolve)、初始化(init)。

new關鍵詞、對象克隆、對象序列化等

  1. 分配內存
    對象的內存分配通常發生在堆內存中(Heap):
    JVM 使用了兩種主要的內存分配方式
分配方式說明
指針碰撞(Bump-the-pointer)(默認用指針碰撞)適用于堆空間規整;分配快,只需移動指針。
空閑列表(Free List)適用于堆空間不規整(存在碎片);需要維護空閑塊鏈表,分配效率低一些。(通常在垃圾回收后出現堆空間不規整)

以上兩種方法都存在并發問題,解決并發問題的方法:

  • CAS(compare and swap)
    虛擬機采用CAS配上失敗重試的方式保證更新操作的原子性來對分配內存空間的動作進行同步處理。
  • 本地線程分配緩沖(Thread Local Allocation Buffer,TLAB)
    把內存分配的動作按照線程劃分在不同的空間之中進行,即每個線程在Java堆中預先分配一小塊內存。通過-XX:+/-UseTLAB參數來設定虛擬機是否使用TLAB(JVM會默認開啟-XX:+UseTLAB),-XX:TLABSize 指定TLAB大小。
  1. 內存初始化(零值初始化)
    分配的內存空間會被零值初始化(不包括對象頭),也就是將對象的實例字段全部設為默認值(0、null、false 等)。如果使用TLAB,這一工作過程也可以提前至TLAB分配時進行。

注意:這只是 JVM 級別的初始化,字段的顯式初始值(如 int a = 10)還未處理。

  1. 設置對象頭
    在這里插入圖片描述

在HotSpot虛擬機中,對象在內存中存儲的布局可以分為3塊區域:對象頭(Header)、 實例數據(Instance Data)和對齊填充(Padding)。 HotSpot虛擬機的對象頭包含兩個主要部分:

  • Mark Word:記錄哈希碼、GC 分代信息、鎖信息等。
  • Klass Pointer:指向對象的類元信息(方法區存的類元數據)(即該對象是哪個類的實例)。

64 位 JVM 默認啟用了指針壓縮(CompressedOops),否則指針是 64 bit,Klass Pointer 就會是 8 byte。

  • 32位對象頭
    在這里插入圖片描述
  • 64位對象頭
    在這里插入圖片描述

數組對象在 JVM 中的對象頭結構 相比普通對象稍有不同,因為它除了包含普通對象頭,還需要4字節存儲數組長度。

分代年齡4字節也驗證了只能小于等于15

  1. 執行< init >方法
    執行< init >方法,即對象按照程序員的意愿進行初始化。對應到語言層面上講,就是為屬性賦值(注意,這與上面的賦零值不同,這是由程序員賦的值),和執行構造方法。

對象大小與指針壓縮

<dependency><groupId>org.openjdk.jol</groupId><artifactId>jol-core</artifactId><version>0.9</version>
</dependency>
import org.openjdk.jol.info.ClassLayout;/*** 計算對象大小*/
public class JOLSample {public static void main(String[] args) {ClassLayout layout = ClassLayout.parseInstance(new Object());System.out.println(layout.toPrintable());System.out.println();ClassLayout layout1 = ClassLayout.parseInstance(new int[]{});System.out.println(layout1.toPrintable());System.out.println();ClassLayout layout2 = ClassLayout.parseInstance(new A());System.out.println(layout2.toPrintable());}// -XX:+UseCompressedOops           默認開啟的壓縮所有指針// -XX:+UseCompressedClassPointers  默認開啟的壓縮對象頭里的類型指針Klass Pointer// Oops : Ordinary Object Pointerspublic static class A {//8B mark word//4B Klass Pointer   如果關閉壓縮-XX:-UseCompressedClassPointers或-XX:-UseCompressedOops,則占用8Bint id;        //4BString name;   //4B  如果關閉壓縮-XX:-UseCompressedOops,則占用8Bbyte b;        //1B Object o;      //4B  如果關閉壓縮-XX:-UseCompressedOops,則占用8B}
}運行結果:
java.lang.Object object internals:OFFSET  SIZE   TYPE DESCRIPTION                               VALUE0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)    //mark word4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)    //mark word     8     4        (object header)                           e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)    //Klass Pointer12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total[I object internals:OFFSET  SIZE   TYPE DESCRIPTION                               VALUE0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)8     4        (object header)                           6d 01 00 f8 (01101101 00000001 00000000 11111000) (-134217363)12     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)16     0    int [I.<elements>                             N/A
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes totalcom.tuling.jvm.JOLSample$A object internals:OFFSET  SIZE               TYPE DESCRIPTION                               VALUE0     4                    (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)4     4                    (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)8     4                    (object header)                           61 cc 00 f8 (01100001 11001100 00000000 11111000) (-134165407)12     4                int A.id                                      016     1               byte A.b                                       017     3                    (alignment/padding gap)                  20     4   java.lang.String A.name                                    null24     4   java.lang.Object A.o                                       null28     4                    (loss due to the next object alignment)
Instance size: 32 bytes
Space losses: 3 bytes internal + 4 bytes external = 7 bytes total
  • 什么是java對象的指針壓縮?
  1. jdk1.6 update14開始,在64bit操作系統中,JVM支持指針壓縮
  2. jvm配置參數:
    -XX:+UseCompressedOops 默認開啟的壓縮所有指針(關閉同時會關閉UseCompressedClassPointers ),
    -XX:+UseCompressedClassPointers 默認開啟的壓縮對象頭里的類型指針Klass Pointer
    (compressed–壓縮、oop(ordinary object pointer)–對象指針)
  3. 啟用指針壓縮:-XX:+UseCompressedOops(默認開啟),禁止指針壓縮:-XX:-UseCompressedOops

指針壓縮(Compressed Oops)主要是為了解決 64 位 JVM 指針過大帶來的內存和性能問題。
64 位指針占用 8 字節,是 32 位指針的兩倍(4 字節)。Java 堆中對象眾多,對象之間通過指針相互引用,指針占內存總量很大。指針變大導致:堆內存占用增加,同樣大小的堆實際能存放的對象數量減少。CPU 緩存壓力變大,緩存命中率下降,性能下降。內存帶寬需求增加,訪問延遲提高。指針壓縮將 64 位指針壓縮成 32 位偏移量,減少內存占用。

  1. 堆內存小于4G時,不需要啟用指針壓縮,jvm會直接去除高32位地址,即使用低虛擬地址空間
  2. 堆內存大于32G時,壓縮指針會失效,會強制使用64位(即8字節)來對java對象尋址,這就會出現堆內存占用增加等問題,所以堆內存不要大于32G為好(最大堆大小 ≈ 壓縮指針可表示的偏移范圍 × 縮放因子(scale)最大堆地址范圍 = 2^32 × 8 = 34,359,738,368 字節 ≈ 32GB)

關于對齊填充:對于大部分處理器,對象以8字節整數倍來對齊填充都是最高效的存取方式。

對象內存分配

對象內存分配流程

在這里插入圖片描述

對象棧上分配(逃逸分析)

JVM通過逃逸分析判斷對象是否只在方法內部使用,若沒有逃逸,可以將對象分配在棧上(棧上分配)或通過標量替換消除對象,減少堆分配壓力。

  • 對象逃逸分析:就是分析對象動態作用域,當一個對象在方法中被定義后,它可能被外部方法所引用,例如作為調用參數傳遞到其他地方中。 JVM對于這種情況可以通過開啟逃逸分析參數(-XX:+DoEscapeAnalysis)來優化對象內存分配位置,使其通過標量替換優先分配在棧上(棧上分配),JDK7之后默認開啟逃逸分析,如果要關閉使用參數(-XX:-DoEscapeAnalysis)
  • 標量替換(標量替換聚合量):通過逃逸分析確定該對象不會被外部訪問,并且對象可以被進一步分解時,JVM不會創建該對象,而是將該對象成員變量分解若干個被這個方法使用的成員變量所代替,這些代替的成員變量在棧幀或寄存器上分配空間,這樣就不會因為沒有一大塊連續空間導致對象內存不夠分配。開啟標量替換參數(-XX:+EliminateAllocations),JDK7之后默認開啟。
  • 標量與聚合量:標量即不可被進一步分解的量,而JAVA的基本數據類型就是標量(如:int,long等基本數據類型以及reference類型等),標量的對立就是可以被進一步分解的量,而這種量稱之為聚合量。而在JAVA中對象就是可以被進一步分解的聚合量。

對象在Eden區分配

新生代分為 Eden區 和兩個 Survivor區(S0、S1)Eden與Survivor區默認8:1:1,新生代對象絕大多數先在 Eden 區分配。大多數對象生命周期短暫,及時GC回收效率高,Eden區空間一般較大,分配速度快。
當 Eden 區沒有足夠空間進行分配時,虛擬機將發起一次Minor GC。
Minor GC和Full GC

  • Minor GC/Young GC:指發生新生代的的垃圾收集動作,Minor GC非常頻繁,回收速度一般也比較快。
    觸發minor gc就會會把eden和from清空,并且把兩個區域還存活的對象移動到to
  • Major GC/Full GC:一般會回收老年代 ,年輕代,方法區的垃圾,Major GC的速度一般會比Minor GC的慢10倍以上。
    就是執行一次Minor GC+老年代的回收+方法區的回收

JVM默認有這個參數-XX:+UseAdaptiveSizePolicy(默認開啟),會導致這個8:1:1比例自動變化,如果不想這個比例有變化可以設置參數-XX:-UseAdaptiveSizePolicy

-XX:+PrintGCDetails 是 JVM 的一個參數,用于打印垃圾回收(GC)時的詳細日志信息。它是調試和性能分析GC行為的常用工具。

大對象直接進入老年代

當Eden區沒有足夠空間進行分配時,虛擬機將發起一次Minor GC,GC期間虛擬機又發現無法存入Survior空間,所以只好把新生代的對象提前轉移到老年代中去,老年代上的空間足夠存放,所以不會出現Full GC。

大對象就是需要大量連續內存空間的對象(比如:字符串、數組)。JVM參數 -XX:PretenureSizeThreshold(單位字節) 可以設置大對象的大小,如果對象超過設置大小會直接進入老年代,不會進入年輕代,這個參數只在 Serial 和ParNew兩個收集器下有效。這樣可以避免為大對象分配內存時的復制操作而降低效率。

長期存活的對象將進入老年代

對象在 Eden 出生并經過第一次 Minor GC 后仍然能夠存活,并且能被 Survivor 容納的話,將被移動到 Survivor 空間中,并將對象年齡設為1。對象在 Survivor 中每熬過一次 MinorGC,年齡就增加1歲,當它的年齡增加到一定程度(默認為15歲,CMS收集器默認6歲,不同的垃圾收集器會略微有點不同)就會被晉升到老年代中。對象晉升到老年代的年齡閾值,可以通過參數 **-XX:MaxTenuringThreshold(最大值硬編碼為 15,解釋對象頭有提到) **來設置。

對象動態年齡判斷

JVM 會根據 Survivor 區當前對象年齡的分布動態決定對象是否需要提前進入老年代,即使它們還沒有達到 MaxTenuringThreshold。
當前放對象的Survivor區域里(to space),一批對象的總大小大于這塊Survivor區域內存大小的50%(-XX:TargetSurvivorRatio可以指定),那么此時大于等于這批對象年齡最大值的對象直接進入老年代

例如Survivor區域里現在有一批對象,年齡1+年齡2+年齡n的多個年齡對象總和超過了Survivor區域的50%,此時就會把年齡n(含)以上的對象都放入老年代。這個規則其實是希望那些可能是長期存活的對象,盡早進入老年代。

動態年齡判斷觸發對象直接進入老年代,發生在每次 Minor GC 執行時的對象復制過程中。

當 Minor GC 把 Eden 和 From 區的存活對象復制到 To Space 時,如果即將進入 To Space 的對象總大小超過 To Space 容量的一半(即 Survivor 區目標大小的一半),會導致這些對象直接進入老年代。

老年代空間分配擔保機制

老年代空間分配擔保機制(也稱為“晉升空間擔保”)是 JVM 中一項重要的安全機制,可以實現提前進行full gc。并且確保在 minor GC 時,幸存對象能夠安全晉升到老年代,不會因為老年代空間不足導致堆內存溢出或對象丟失。
擔保機制的流程:

  1. minor GC 準備階段:JVM 會計算老年代剩余可用空間是否小于年輕代里現有的所有對象大小之和(包括垃圾對象)
  2. 如果空間足夠,minor GC 繼續執行,晉升操作順利完成。
  3. 如果空間不足,就會看一個-XX:-HandlePromotionFailure(jdk1.8默認就設置了)的參數是否設置了,如果有這個參數,就會看看老年代的可用內存大小,是否大于之前每一次minor gc后進入老年代的對象的平均大小。老年代的可用內存大小依然不足之前進入老年代的平均大小就full gc,足夠則minor gc
  4. 如果老年代剩余空間不足并且參數沒有設置,就會觸發一次full gc,對老年代和年輕代一起回收一次垃圾,如果回收完還是沒有足夠空間存放新的對象就會發生"OOM"

當然,如果minor gc之后剩余存活的需要挪動到老年代的對象大小還是大于老年代可用空間,那么也會觸發full gc,full gc完之后如果還是沒有空間放minor gc之后的存活對象,則也會發生“OOM”

對象內存回收

引用計數法(jvm一般不用)

每個對象維護一個引用計數器(refCount),每當有一個地方引用它,計數器加 1;引用失效時,計數器減 1。當引用計數為 0,就說明該對象不再被使用,可以被回收。致命缺點:循環引用問題。引用計數法無法處理兩個對象互相引用但整體不可達的情況。

public class ReferenceCountingGc {Object instance = null;public static void main(String[] args) {ReferenceCountingGc objA = new ReferenceCountingGc();ReferenceCountingGc objB = new ReferenceCountingGc();objA.instance = objB;objB.instance = objA;objA = null;objB = null;}
}

除了對象objA 和 objB 相互引用著對方之外,這兩個對象之間再無任何引用。但是他們因為互相引用對方,導致它們的引用計數器都不為0,于是引用計數算法無法通知 GC 回收器回收他們。

可達性分析算法(jvm一般使用)

在這里插入圖片描述
將“GC Roots” 對象作為起點,從這些節點開始向下搜索引用的對象,找到的對象都標記為非垃圾對象,其余未標記的對象都是垃圾對象
常見的 GC Roots 包括:

GC Roots 類型示例
虛擬機棧中的引用變量(棧幀中的局部變量)方法中定義的局部變量、參數等
方法區中靜態字段引用的對象static 引用的對象
方法區中常量引用的對象字面量池中的字符串,如 "abc"
本地方法棧中的 JNI 引用Native 方法中用到的對象
運行時的活動線程啟動的線程本身不會被 GC 回收
類加載器系統/應用類加載器

因為stw了,還在活躍但是被暫停的棧幀的對象不該被回收

三色標記(并發垃圾回收器(如 CMS、G1))

三色標記算法(Tri-color Marking)是現代垃圾回收(GC)中常用的可達性分析方法,特別用于并發和增量標記階段,它有效避免了標記過程中出現對象“丟失”的問題。

三色含義
白色(White)表示未被訪問的對象集合。初始時,所有對象都是白色。標記完成后,仍為白色的對象被判定為不可達對象,需要回收。
灰色(Gray)示已經被發現,但其引用的對象尚未完全掃描的對象集合。需要掃描灰色對象的引用,進一步遞歸標記。
黑色(Black)表示該對象以及它引用的所有對象都已經被掃描完成。

算法流程:

  1. 初始化:所有對象為白色。從 GC Roots 開始,將這些根對象標記為灰色。
  2. 掃描灰色對象:從灰色對象集合中取出一個對象,掃描它引用的所有白色對象。發現的白色對象變成灰色,加入待掃描集合。掃描完成后,當前對象變黑色。
  3. 重復掃描灰色對象,直到灰色集合為空。此時所有可達對象都變成了黑色。剩下的白色對象即不可達,準備回收。

三色標記通過保持“黑色對象不引用白色對象”的不變式,保證標記的正確性。
當應用線程修改引用時,如果黑色對象引用變成了白色對象,GC必須檢測到這個“新引用的白色對象”。
GC使用寫屏障(Write Barrier)機制,捕獲這類修改,并將被新引用的白色對象標記為灰色,加入掃描隊列,保證不會遺漏。

常見引用類型

Java 四種引用類型(按強弱排序):

引用類型類名是否會阻止 GC回收時機描述
強引用普通變量引用(默認)會阻止回收永遠不會被 GC 回收,除非手動斷開引用
軟引用java.lang.ref.SoftReference一定條件下回收內存不足時才會被回收,適合緩存
弱引用java.lang.ref.WeakReference不阻止回收下一次 GC 就會被回收
虛引用java.lang.ref.PhantomReference完全不保留被 GC 回收前就進入 ReferenceQueue,僅作通知
  • 強引用:普通的變量引用
public static User user = new User();//靜態變量
public Object foo() {Object obj = new Object();//方法內的變量引用return obj;
}
foo();//返回的對象不可達,可能會被回收
Object result = foo();//返回的對象賦值了屬于強引用
  • 軟引用:將對象用SoftReference軟引用類型的對象包裹,正常情況不會被回收,但是GC做完后發現釋放不出空間存放新的對象,則會把這些軟引用的對象回收掉。軟引用可用來實現內存敏感的高速緩存。
public static SoftReference<User> user = new SoftReference<User>(new User());

例如瀏覽器的后退按鈕。按后退時,這個后退時顯示的網頁內容是重新進行請求還是從緩存中取出呢?

  1. 如果一個網頁在瀏覽結束時就進行內容的回收,則按后退查看前面瀏覽過的頁面時,需要重新構建
  2. 如果將瀏覽過的網頁存儲到內存中會造成內存的大量浪費,甚至會造成內存溢出
    這時候軟引用就可以實現,在內存充足的時候緩存,不足的時候gc,讓程序重新加載頁面。
  • 弱引用:將對象用WeakReference軟引用類型的對象包裹,弱引用跟沒引用差不多,GC會直接回收掉,很少用
public static WeakReference<User> user = new WeakReference<User>(new User());
  • 虛引用:虛引用也稱為幽靈引用或者幻影引用,它是最弱的一種引用關系,幾乎不用

finalize()方法最終判定對象是否存活

finalize() 是 Java 中 java.lang.Object 類定義的一個方法,它在垃圾回收器準備回收對象之前被調用,可以讓對象有機會進行清理操作。

即使在可達性分析算法中不可達的對象,也并非是“非死不可”的,這時候它們暫時處于“緩刑”階段,要真正宣告一個對象死亡,至少要經歷再次標記過程。
標記的前提是對象在進行可達性分析后發現沒有與GC Roots相連接的引用鏈。

  1. 第一次標記并進行一次篩選。
    篩選的條件是此對象是否有必要執行finalize()方法。當對象沒有覆蓋finalize方法,對象將直接被回收。
  2. 第二次標記
    如果這個對象覆蓋了finalize方法,會進行第二次標記,如果對象還是應該被回收就真的被回收了。
    缺點與問題:
  • 不確定性:finalize() 什么時候被調用不確定,依賴 GC 時間,可能很晚或根本不調用。
  • 性能開銷大:有 finalize() 方法的對象回收會更慢,垃圾回收效率降低。
  • 復活問題:在 finalize() 中可以讓對象“復活”(重新被引用),導致難以預測的行為。
  • 可能導致內存泄漏:如果對象在 finalize() 中復活,但不被及時清理。

finalize()方法的運行代價高昂, 不確定性大, 無法保證各個對象的調用順序, 如今已被官方明確聲明為不推薦使用的語法。finalize()方法的運行代價高昂, 不確定性大, 無法保證各個對象的調用順序, 如今已被官方明確聲明為不推薦使用的語法。

如何判斷一個類是無用的類

方法區主要回收的是無用的類,那么如何判斷一個類是無用的類呢?
類需要同時滿足下面4個條件才能算是 “無用的類” :

  • 該類所有的對象實例都已經被回收,也就是 Java 堆中不存在該類的任何實例。
  • 加載該類的 ClassLoader 已經被回收。
  • 該類對應的 java.lang.Class 對象沒有在任何地方被引用,沒有在任何地方通過反射訪問該類的方法。
  • 該類的靜態變量/常量沒有被外部引用,靜態變量/常量持有的強引用會阻止類的卸載,因此靜態變量/常量應當不被引用或已置空。

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

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

相關文章

Navicat 技術指引 | TiDB 的 AI 查詢交互功能

目前&#xff0c;Navicat 兩款工具支持對 TiDB 數據庫的管理開發功能&#xff1a;一款是旗艦款 Navicat Premium&#xff0c;另一款是其輕量化功能的 Navicat Premium Lite&#xff08;官方輕量級免費版&#xff09;。Navicat 自版本 17.1 開始支持 TiDB 7。它支持的系統有 Win…

以list為輸入條件,查詢數據庫表,java中的mapper層和mybatis層應該怎么寫?

根據一個 List 中的兩個字段 rangeCode 和 unitcd&#xff0c;查詢數據庫表 model_engineering_spatial_unit。這個需求在 Java MyBatis 項目中非常常見&#xff0c;下面我將為你詳細寫出 Mapper 接口&#xff08;Java&#xff09; 和 MyBatis XML 映射文件 的寫法。 ? 前提…

pyspark 創建DataFrame

from pyspark.sql import SparkSession from pyspark.sql import StructType, StructField, IntegerType,StringType spark SparkSession.builder.appName(test).getOrCreate() 1、 從列表中創建DataFrame data [(1,"alice"),(2,Blob),(3,Charlie)] columns [&qu…

Vim:從入門到進階的高效文本編輯器之旅

目錄 一、Vim簡介 二、Vim的基礎操作 2.1 進入和退出Vim 2.2 Vim的三種模式 2.3 基礎移動 三、Vim的高效編輯技巧 3.1 文本編輯 3.2 文本刪除與修改 3.3 復制與粘貼 四、Vim的進階使用 4.1 搜索與替換 4.2 寄存器與宏 4.3 插件與配置 五、結語 在編程界&#xff0…

Docker基礎理論與阿里云Linux服務器安裝指南

文章目錄 一、Docker核心概念二、阿里云環境準備三、Docker安裝與配置四、核心容器部署示例五、開發環境容器化六、運維管理技巧七、安全加固措施 一、Docker核心概念 容器化本質&#xff1a; 輕量級虛擬化技術&#xff0c;共享主機內核進程級隔離&#xff08;cgroups/namespac…

c#使用筆記之try catch和throw

一、try catch 一種報錯的捕捉機制&#xff0c;try塊里運行的代碼出現錯誤的時候就會去執行catch塊所以一般catch塊里都是把錯誤打印出來或者保存到log日志里&#xff1b; 1.1、具體使用 catch可以用&#xff08;&#xff09;來選擇捕捉什么類型的錯誤&#xff0c;一般用Exc…

(新手友好)MySQL學習筆記(9):索引(常見索引類型,查找結構的發展(二分查找法,二叉搜索樹,平衡二叉樹,B樹,B+樹))

目錄 索引 常見索引類型 B樹 二分查找法 二叉搜索樹和平衡二叉樹 B樹和B樹 索引 index&#xff0c;是存儲引擎用于快速找到數據的一種數據結構。 MySQL默認使用InnoDB存儲引擎&#xff0c;該存儲引擎是最重要&#xff0c;使用最廣泛的&#xff0c;除非有非常特別的原因需要使用…

進程間通信1(匿名管道)Linux

1 進程間通信的必要性 首先要明確進程間是相互獨立的&#xff08;獨享一份虛擬地址空間&#xff0c;頁表&#xff0c;資源&#xff09;&#xff0c;那怎么樣才能使得兩個進程間實現資源的發送&#xff1f;所以&#xff0c;兩個進程一定需要看到同一份資源&#xff0c;并且?個…

CAN2.0、DoIP、CAN-FD汽車協議詳解與應用

一、CAN2.0 協議詳解與應用示例 1. 技術原理與特性 協議架構&#xff1a;基于 ISO 11898 標準&#xff0c;采用載波監聽多路訪問 / 沖突檢測&#xff08;CSMA/CD&#xff09;機制&#xff0c;支持 11 位&#xff08;CAN2.0A&#xff09;或 29 位&#xff08;CAN2.0B&#xff…

使用nvm管理npm和pnpm

1.使用nvm管理npm // 查看nvm版本 nvm -v // 查看可安裝的 node 版本 nvm ls-remote // 安裝指定 node 版本 nvm install 24.0.0 // 查看當前已安裝的 node 版本及當前使用的版本 nvm list // 使用某個版本 node nvm use 24.0.0 // 卸載指定 node 版本 nvm uninstall 16.20.1…

YOLO11+QT6+Opencv+C++訓練加載模型全過程講解

實現效果&#xff1a; Yolov11環境搭建&#xff08;搭建好的可以直接跳過&#xff09; 最好使用Anconda進行包管理&#xff0c;安裝可參考【文章】。下面簡單過一下如何快速部署環境。如果搭建過或可以參考其他文章可以跳過Yolo11環境搭建這一章節。總體來說Yolov11環境搭建越…

Python 腳本,用于將 PDF 文件高質量地轉換為 PNG 圖像

import os import fitz # PyMuPDF from PIL import Image import argparse import logging from tqdm import tqdm# 配置日志 logging.basicConfig(levellogging.INFO, format%(asctime)s - %(levelname)s - %(message)s) logger logging.getLogger(PDF2PNG)def convert_pdf_…

【CUDA GPU 支持安裝全攻略】PyTorch 深度學習開發者指南

PyTorch 的 CUDA GPU 支持 安裝五條鐵律&#xff08;最新版 2025 修訂&#xff09;&#xff08;適用于所有用戶&#xff09;-CSDN博客 是否需要預先安裝 CUDA Toolkit&#xff1f;——按使用場景分級推薦及進階說明-CSDN博客 “100% 成功的 PyTorch CUDA GPU 支持” 安裝攻略…

Cyberith 運動模擬器Virtualizer2:提升虛擬現實沉浸體驗

奧地利Cyberith公司是一家專注于虛擬現實&#xff08;VR&#xff09;互動解決方案的創新型科技企業&#xff0c;以其研發的Virtualizer虛擬現實步態模擬設備而聞名。該公司的核心技術體現在其設計和制造的全方位跑步機式VR交互平臺上&#xff0c;使得用戶能夠在虛擬環境中實現自…

常見的數據處理方法有哪些?ETL中的數據處理怎么完成

在數字化轉型縱深推進的背景下&#xff0c;數據作為新型生產要素已成為驅動企業戰略決策、科研創新及智能化運營的核心戰略資產。數據治理價值鏈中的處理環節作為關鍵價值節點&#xff0c;其本質是通過系統化處理流程將原始觀測數據轉化為結構化知識產物&#xff0c;以支撐預測…

WHAT - 為甲方做一個官網(二)- 快速版

文章目錄 一、明確需求優先級&#xff08;快速決策&#xff09;二、推薦零代碼/低代碼工具&#xff08;附對比&#xff09;方案1&#xff1a;低代碼建站平臺&#xff08;適合無技術用戶&#xff0c;拖拽式操作&#xff09;方案2&#xff1a;CMS系統&#xff08;適合內容更新頻繁…

音視頻之H.264視頻編碼傳輸及其在移動通信中的應用

系列文章&#xff1a; 1、音視頻之視頻壓縮技術及數字視頻綜述 2、音視頻之視頻壓縮編碼的基本原理 3、音視頻之H.264/AVC編碼器原理 4、音視頻之H.264的句法和語義 5、音視頻之H.264/AVC解碼器的原理和實現 6、音視頻之H.264視頻編碼傳輸及其在移動通信中的應用 7、音視…

C#語言入門-task2 :C# 語言的基本語法結構

下面從四個方面對C#的基本語法進行簡單介紹&#xff1a; 1. 數據類型 C#的類型可分為值類型和引用類型。值類型變量直接存儲數據&#xff0c;引用類型變量則存儲對象的引用。 值類型&#xff1a;涵蓋整數類型&#xff08;像int、long&#xff09;、浮點類型&#xff08;例如…

c#筆記之類的常量、字段和屬性

學習內容: 一、字段 字段是為了對象或者類型存儲數據的,可以表達一個對象或者類型的狀態;也叫做成員變量;注意字段是在類里面聲明的;在方法里聲明的是局部變量; 1.1實例字段 用來表示每個實例的狀態;比如一個students類;要了解一個學生一般看名字和成績;所以名字和…

Linux 常用命令(入門)

Linux 常用命令 一、Linux 命令基礎 (一)命令格式 Linux 命令的一般格式為:command [-options] [parameter1] … 。其中,command 是命令名,通常是相應功能的英文單詞或其縮寫;[-options] 是選項,用于對命令進行控制,可省略;parameter1 … 是傳給命令的參數,可以是…