上一篇地址:持續總結中!2024年面試必問 100 道 Java基礎面試題(四十)-CSDN博客
八十一、Java內存模型是什么?
Java內存模型(Java Memory Model, JMM)是Java虛擬機(JVM)的一個核心概念,它定義了Java程序中各種變量(線程共享變量)的訪問規則,以及在并發環境下,如何保證這些變量的內存一致性。JMM是Java并發編程的基礎,它解決了多線程環境下的內存一致性問題。
Java內存模型的主要目標
-
定義主內存與工作內存:JMM定義了主內存(Main Memory)和工作內存(Working Memory)。主內存是所有線程共享的內存區域,用于存儲共享變量。工作內存是每個線程獨立的內存區域,線程對共享變量的操作首先在工作內存中進行,然后再與主內存同步。
-
保證內存一致性:在并發編程中,JMM確保在不同的線程間,對共享變量的讀寫操作能夠按照預期的順序執行,從而保證多線程環境下的內存一致性。
-
定義原子性、可見性和有序性:JMM規定了哪些操作是原子操作,以及線程如何感知其他線程中共享變量的更改(可見性),以及線程如何保證操作的有序性。
原子性、可見性和有序性
-
原子性:原子性是指一個操作或者一系列操作在執行過程中不會被其他線程中斷。
-
可見性:可見性是指當一個線程修改了共享變量的值,其他線程能夠立即看到這個修改。
-
有序性:有序性是指在程序中,按照代碼的先后順序執行操作。
同步塊和鎖
-
同步塊:Java中的
synchronized
關鍵字可以用來創建同步塊,確保同一時刻只有一個線程可以執行該代碼塊。 -
鎖:在JMM中,鎖提供了一種機制,確保原子性、可見性和有序性。當線程持有鎖時,其他線程必須等待直到鎖被釋放。
內存屏障
- 內存屏障:JMM通過內存屏障(Memory Barrier)來禁止特定類型的編譯器和處理器重排序,確保指令的執行順序。
與硬件的交互
- 控制硬件行為:JMM還定義了JVM應該如何與底層硬件交互,以確保即使在不同的硬件和操作系統上,Java程序的內存一致性行為也是相同的。
示例代碼
public class Counter {private int count = 0;public synchronized void increment() {count++;}public int getCount() {return count;}
}
在這個示例中,Counter
類的increment
方法是同步的,這意味著在同一時間只能有一個線程進入這個方法。這保證了count
變量的原子性、可見性和有序性。
注意事項
- 并發編程的復雜性:JMM的引入增加了并發編程的復雜性,但同時也提供了強大的控制手段。
- 理解JMM:深入理解JMM對于編寫正確的并發程序至關重要。
- 使用并發庫:Java提供了一些并發庫(如
java.util.concurrent
包),它們基于JMM構建,可以簡化并發編程。
總結來說,Java內存模型是Java并發編程的核心,它定義了多線程環境下的內存一致性規則,幫助開發者理解并控制線程之間的內存交互。
八十二、Java中的垃圾回收機制是如何工作的?
Java中的垃圾回收(Garbage Collection, GC)機制是一種自動內存管理功能,它負責監控程序使用內存的情況,自動回收不再使用的對象,從而防止內存泄漏和節省內存資源。以下是Java垃圾回收機制的詳細解釋:
對象創建和內存分配
-
當Java程序創建對象時,它們被分配到堆內存中。堆內存被分為不同的區域,如新生代(Young Generation)、老年代(Old Generation)和永久代(Permanent Generation,Java 8之后被元空間取代)。
-
新生代是新對象的初始分配區域,它進一步分為Eden區、兩個Survivor區(S0和S1)。
對象的生命周期
-
新生代:新對象首先在Eden區分配。當Eden區滿時,觸發一次Minor GC,將存活的對象復制到一個Survivor區。
-
Survivor區:在Eden區發生GC后,存活的對象被移動到Survivor區。如果對象在Survivor區再次經過GC仍然存活,它們將被提升到老年代。
-
老年代:老年代用于存放長壽命的對象,當老年代空間不足時,會觸發Full GC(或Major GC),對整個堆內存進行垃圾回收。
垃圾回收算法
-
標記-清除:這是最基本的GC算法,它首先標記所有需要回收的對象,然后清除這些被標記的對象。
-
復制算法:在新生代中使用,它將內存分為兩個區域,每次只使用一個區域。垃圾回收時,將存活的對象復制到另一個區域,并清空當前區域。
-
標記-整理:在老年代中使用,它結合了標記-清除算法,同時移動存活對象,以減少內存碎片。
-
分代收集:基于對象的生命周期,將對象分配到不同的代中,新生代和老年代使用不同的垃圾回收策略。
垃圾回收器
-
Serial GC:單線程的垃圾回收器,適用于小型應用。
-
Parallel GC:使用多個線程進行垃圾回收,適用于多核處理器。
-
Concurrent Mark Sweep (CMS):并發標記清除垃圾回收器,旨在減少GC暫停時間。
-
G1 (Garbage-First):一種服務器端的垃圾回收器,旨在替代CMS,它將堆分割成多個小塊,可以更靈活地進行垃圾回收。
如何觸發垃圾回收
-
顯式觸發:通過調用
System.gc()
可以建議JVM進行垃圾回收,但JVM可以選擇忽略這個建議。 -
隱式觸發:當堆內存不足時,JVM會自動觸發垃圾回收。
注意事項
-
性能影響:雖然垃圾回收可以自動管理內存,但頻繁的GC會降低程序性能。
-
對象引用:對象的生命周期不僅取決于是否被引用,還取決于引用的強度(如強引用、軟引用、弱引用)。
-
內存泄漏:未能正確釋放不再使用的對象引用會導致內存泄漏。
-
監控和調優:可以通過JVM監控工具來觀察GC行為,并根據需要調整垃圾回收策略。
總結來說,Java的垃圾回收機制通過自動監測內存使用情況并回收不再使用的對象來管理工作內存。了解垃圾回收的工作原理和垃圾回收器的行為對于編寫高效的Java程序和進行性能調優非常重要。