一.垃圾回收機制
1. 簡述一下一個引用對象的生命周期?
(創建>使用>釋放)
new創建對象並分配內存
對象初始化
對象操作、使用
資源清理(非托管資源)
GC垃圾回收
2. 創建下面對象實例,需要申請多少內存空間?
public class User { public int Age { get; set; } public string Name { get; set; } public string _Name = "123" + "abc"; public List<string> _Names; }
40字節內存空間。
3. 什么是垃圾?
一個變量如果在其生存期內的某一時刻已經不再被引用,那么,這個對象就有可能成為垃圾。
4. GC是什么,簡述一下GC的工作方式?
在公共語言運行時 (CLR) 中,垃圾回收器 (GC) 用作自動內存管理器。 垃圾回收器管理應用程序的內存分配和釋放。
她的基本工作原理就是遍歷托管堆中的對象,標記哪些被使用對象(哪些沒人使用的就是所謂的垃圾),然后把可達對象轉移到一個連續的地址空間(也叫壓縮),其余的所有沒用的對象內存被回收掉。
5. GC進行垃圾回收時的主要流程是?
(1)標記 ,找到並創建所有活動對象的列表。
(2)重定位 ,用於更新對將要壓縮的對象的引用。
(3)壓縮 ,用於回收由死對象占用的空間,並壓縮幸存的對象。 壓縮階段將垃圾回收中幸存下來的對象移至段中時間較早的一端。
6. GC在哪些情況下回進行回收工作?
(1)系統具有低的物理內存。 這是通過 OS 的內存不足通知或主機指示的內存不足檢測出來。
(2)由托管堆上已分配的對象使用的內存超出了可接受的閾值。 隨着進程的運行,此閾值會不斷地進行調整。
(3)調用 GC.Collect 方法。 幾乎在所有情況下,你都不必調用此方法,因為垃圾回收器會持續運行。 此方法主要用於特殊情況和測試。
7. using() 語法是如何確保對象資源被釋放的?如果內部出現異常依然會釋放資源嗎?
using() 只是一種語法形式,其本質還是try…finally的結構,可以保證Dispose始終會被執行。
8. 解釋一下C#里的析構函數?為什么有些編程建議里不推薦使用析構函數呢?
C#里的析構函數其實就是終結器Finalize,因為長得像C++里的析構函數而已。
有些編程建議里不推薦使用析構函數要原因在於:第一是Finalize本身性能並不好;其次很多人搞不清楚Finalize的原理,可能會濫用,導致內存泄露,因此就干脆別用了
9. Finalize() 和 Dispose() 之間的區別?
Finalize() 和 Dispose()都是.NET中提供釋放非托管資源的方式,他們的主要區別在於執行者和執行時間不同:
finalize由垃圾回收器調用;dispose由對象調用。
finalize無需擔心因為沒有調用finalize而使非托管資源得不到釋放,而dispose必須手動調用。
finalize不能保證立即釋放非托管資源,Finalizer被執行的時間是在對象不再被引用后的某個不確定的時間;而dispose一調用便釋放非托管資源。
只有class類型才能重寫finalize,而結構不能;類和結構都能實現IDispose。
另外一個重點區別就是終結器會導致對象復活一次,也就說會被GC回收兩次才最終完成回收工作,這也是有些人不建議開發人員使用終結器的主要原因。
10. Dispose和Finalize方法在何時被調用?
Dispose一調用便釋放非托管資源;
Finalize不能保證立即釋放非托管資源,Finalizer被執行的時間是在對象不再被引用后的某個不確定的時間;
11. .NET中的托管堆中是否可能出現內存泄露的現象?
是的,可能會。比如:
不正確的使用靜態字段,導致大量數據無法被GC釋放;
沒有正確執行Dispose(),非托管資源沒有得到釋放;
不正確的使用終結器Finalize(),導致無法正常釋放資源;
其他不正確的引用,導致大量托管對象無法被GC釋放;
12. 在托管堆上創建新對象有哪幾種常見方式?
new一個對象;
字符串賦值,如string s1=”abc”;
值類型裝箱;
二,什么是多態?
通過繼承實現的不同對象,調用相同的方法,產生不同的執行結果.
C#支持兩種類型的多態,編譯時的多態和運行時的多態。
(1)編譯時的多態:
編譯時的多態是通過重載來實現的,對於非虛的成員來說,系統在編譯時,根據傳遞的參數類型,個數以及返回類型的不同決定實現不同的操作.
重載:
public int Sum(int x,int y)
public int Sum(int x,int y,int z)
public double Sum (Double x,Double y)
重載特點:
方法名稱必須相同
參數列表必須不同
返回值類型可以不同
(2)運行時的多態:
運行時的多態是指系統直到運行時,才根據實際情況實現何種操作.
運行時的多態可以通過virtual-override(虛成員覆蓋實現)以及abstract-override(抽象方法覆蓋實現)兩種方式來實現.
通過override實現覆寫注意的幾點
只有虛方法和抽象方法才能被覆寫
子類和基類中的方法必須具有相同的方法名稱,參數個數,參數類型以及返回值類型.
總結:
編譯時的多態使運行速度更快,就像const編譯時解析.
運行時的多態帶來了高度靈活以及抽象的特點.
三、鎖,除了lock還有哪些鎖?
基元線程同步構造分為:基元用戶模式構造和基元內核模式構造,兩種同步構造方式各有優缺點,而混合構造(如lock)就是綜合兩種構造模式的優點。
1、用戶模式構造
(1) System.Threading.Interlocked:易失構造,它在包含一個簡單數據類型的變量上執行原子性的讀或寫操作。
(2)Thread.VolatileRead 和 Thread.VolatileWrite:互鎖構造,它在包含一個簡單數據類型的變量上執行原子性的讀和寫操作。
2、內核模式構造的主要有兩種方式,以及基於這兩種方式的常見的鎖:
基於事件:如AutoResetEvent、ManualResetEvent
基於信號量:如Semaphore
Mutex
3、混合線程同步
SemaphoreSlim、ManualResetEventSlim、Monitor、ReadWriteLockSlim
--------------------------------------EF相關 ------------------------------------
四、使用EF update 怎么保證在並發時數據正確?
五、EF如何處理並發?
什么叫並發:當多個用戶同時更新同一數據的時候,由於更新可能導致數據的不一致性,使得程序的業務數據發生錯誤,這種情況可以稱之為並發。
並發又分為兩種:樂觀並發 與 悲觀並發
樂觀並發:即系統允許多個用戶同時修改同一條記錄,系統會預先定義由數據並發所引起的並發異常處理模式,去處理修改后可能發生的沖突
當出現樂觀並發時應該怎么處理呢,通常有如下三種處理方法
a 保留最后一次對象修改的值
b 保留最初的修改值
c 合並修改值
悲觀並發:在同一時刻只允許一個用戶修改相同數據,直接用Lock 與 unLock就可以處理.
六、事務的四大特性:
1 、原子性 (atomicity):強調事務的不可分割.
事務是數據庫的邏輯工作單位,事務中包含的各操作要么都做,要么都不做
2 、一致性 (consistency):事務的執行的前后數據的完整性保持一致.
事務執行的結果必須是使數據庫從一個一致性狀態變到另一個一致性狀態。因此當數據庫只包含成功事務提交的結果時,就說數據庫處於一致性狀態。如果數據庫系統 運行中發生故障,有些事務尚未完成就被迫中斷,這些未完成事務對數據庫所做的修改有一部分已寫入物理數據庫,這時數據庫就處於一種不正確的狀態,或者說是 不一致的狀態。
3 、隔離性 (isolation):一個事務執行的過程中,不應該受到其他事務的干擾
一個事務的執行不能其它事務干擾。即一個事務內部的操作及使用的數據對其它並發事務是隔離的,並發執行的各個事務之間不能互相干擾。
4 、持續性 (durability) :事務一旦結束,數據就持久到數據庫
也稱永久性,指一個事務一旦提交,它對數據庫中的數據的改變就應該是永久性的。接下來的其它操作或故障不應該對其執行結果有任何影響。
七、那么在沒有對事務進行隔離時會發生哪些危害了?
臟讀:當一個事務讀取數據修改后以經SaveChange但事務還沒有提交,此時另外一個事務就讀取了該數據,此時的數據就是臟數據,這一過程就是臟讀
不可重復讀:是指在一個事務內,多次讀同一數據。在這個事務還沒有結束時,另外一個事務也訪問該同一數據。那么,在第一個事務中的兩次讀數據之間,由於第二個事務的修改,那么第一個事務兩次讀到的的數據可能是不一樣的。這樣就發生了在一個事務內兩次讀到的數據是不一樣的這一過程就是不可重復讀
幻讀:一個事務針對一張表的所有數據進行讀取修改,而此時另一個事務向表中插入了一條數據,則第一個事務數據不包含新數據,像出現幻覺一樣,這一過程就是幻讀。
避免不可重復讀需要鎖行。
避免幻影讀則需要鎖表。
八、EF四種隔離級別
01:Read uncommitted(讀未提交):最低級別,任何情況都會發生。
02:Read Committed(讀已提交):可避免臟讀的發生。
03:Repeatable read(可重復讀):可避免臟讀、不可重復讀的發生。
04:Serializable(串行化):避免臟讀、不可重復讀,幻讀的發生。
四種隔離級別:Seralizable 級別最高,最低的是 Read uncommitted 級別,級別越高,執行效率就越低,隔離級別的設置只對當前鏈接有效,對.NET 操作數據庫來說,一個 Connection 對象相當於一個鏈接。
01:MySQL 數據庫的默認隔離級別是Repeatable read 級別。
02:Oracle數據庫中,只支持 Seralizable 和 Read committed級別,默認的是 Read committed 級別。
03:SQL Server 數據庫中,默認的是Read committed 級別。
http://www.zyiz.net/tech/detail-182425.html
九、efcore事務的幾種方法?
1、默認事務(SaveChanges)
(1).默認情況下,如果數據庫提供程序支持事務,單個 SaveChanges() 調用中的所有變更都會在一個事務中被提交。如果其中任何一個變更失敗了, 那么事務就會回滾,沒有任何變更會被應用到數據庫。這意味着 SaveChanges() 能夠確保要么成功保存,要么在發生錯誤時不對數據庫做任何修改。
(2).關閉默認事務:context.Database.AutoTransactionsEnabled = false;
2. DbContextTransaction
(1). 使用方式
BeginTransaction開啟事務、Commit提交事務、Rollback回滾事務、Dispose銷毀,如果用Using包裹的話,不再需要手動Rollback,走完Using會自動回滾。如果不用Using包裹事務,就需要在Catch中手動RollBack回滾,並且最好最后手動的Dispose一下。(如SameDbContext文件夾中的Test1和Test2方法)
(2). 使用場景
A. 同一個上下文多個SaveChanges的方法(如:自增主鍵后續要用到)、SaveChanges和EF調用SQL語句混用
3. 環境事務 TransactionScope
(1)使用方式
new TransactionScope創建事務、Complete提交事務、 Transaction.Current.Rollback();回滾事務、Dispose銷毀對象。如果用Using包裹的話,不再需要手動Rollback,走完Using會自動回滾。如果不用Using包裹事務,就需要在Catch中手動RollBack回滾,並且最好最后手動的Dispose一下。TransactionScope有三個屬性:IsolationLevel(隔離等級),Timeout(超時),TransactionScopeOption(選項)
(2)用途
A. 同一個上下文的事務。(多個SaveChanges(自增主鍵后續用到的情況)、SaveChanges和EF調用SQL語句混用)(如Test1方法)
B. 多種數據庫技術訪問同一個數據庫的事務 (如Test2方法)
C. 同一個數據庫多個不同的上下文是支持的(如Test3方法)
D. 不同數據庫的上下文是不支持的,(如Test4方法,開啟msdtc服務的步驟: cmd命令→ net start msdtc ,然后發現報錯:This platform does not support distributed transactions.說明目前Core平台下不支持分布式事務)
參考:
http://www.zyiz.net/tech/detail-182188.html
http://www.zyiz.net/tech/detail-182154.html
十、使用EF update 怎么保證在並發時數據正確?
1、RowVersion ( TimeStamp ) 時間戳
EF實現Rowversion 並發控制 需要借助 TimeStamp 標示 ,並且一個類只能有 一個此標示,標示的必須是byte[]類型。使用Rowversion會對整行數據進行並發檢測。
2、 ConcurrencyCheck
有些時候並不需要控制針對整條記錄的並發,只需要控制某個列的數據不會出現臟操作就ok,這個時候 就使用ConcurrencyCheck 。你必須將ConcurrencyCheck特性添加到實體需要控制並發的非主鍵屬性上,使實體框架可以將所有標記的列包含到更新語句的Where子句中。
3、 DbUpdateConcurrencyException
您可以通過EF實體框架引發的DbUpdateConcurrencyException異常處理來解決沖突。
------------------------------------------------------------------------------
二十、jwt的組成有那幾部分?
樣式:"xxxxxxxxxxxx.xxxxxxxxxxxxx.xxxxxxxxxxxxxxxx"由三部分組成.
(1).Header頭部:{\"alg\":\"HS256\",\"typ\":\"JWT\"}基本組成,也可以自己添加別的內容,然后對最后的內容進行Base64編碼.
(2).Payload負載:iss、sub、aud、exp、nbf、iat、jti基本參數,也可以自己添加別的內容,然后對最后的內容進行Base64編碼.
(3).Signature簽名:將Base64后的Header和Payload通過.組合起來,然后利用Hmacsha256+密鑰進行加密。
二十一、jwt的安全性有哪些建議?
1、SecurityKey一定要保管好;
2、簽名一定要有,校驗簽名並且不接受非法的簽名;( 簽名解決了數據傳輸過程中參數被篡改的風險)
3、payload增加時間戳減少重放攻擊;
4、payload里不存放敏感信息,若有請用臨時票據token形式的;
5、接口傳輸采用https協議;
https://www.jianshu.com/p/836df92c06eb
二十一、什么是面向對象?面向對象的三大特性和五大原則是什么?
面向對象的方法主要是把事物給對象化,包括其屬性和行為。面向對象編程更貼近實際生活的思想。總體來說面向對象的底層還是面向過程,面向過程抽象成類,然后封裝,方便使用就是面向對象(萬物皆對象)。
三大基本特性:封裝,繼承,多態
封裝
封裝,就是把客觀事物封裝成抽象的類,並且類可以把自己的數據和方法只讓可信的類或者對象操作,對不可信的進行信息隱藏。一個類就是一個封裝了數據以及操作這些數據的代碼的邏輯實體。在一個對象內部,某些代碼或某些數據可以是私有的,不能被外界訪問。通過這種方式,對象對內部數據提供了不同級別的保護,以防止程序中無關的部分意外的改變或錯誤的使用了對象的私有部分。
繼承
繼承,指可以讓某個類型的對象獲得另一個類型的對象的屬性的方法。它支持按級分類的概念。繼承是指這樣一種能力:它可以使用現有類的所有功能,並在無需重新編寫原來的類的情況下對這些功能進行擴展。 通過繼承創建的新類稱為“子類”或“派生類”,被繼承的類稱為“基類”、“父類”或“超類”。繼承的過程,就是從一般到特殊的過程。要實現繼承,可以通過 “繼承”(Inheritance)和“組合”(Composition)來實現。繼承概念的實現方式有二類:實現繼承與接口繼承。實現繼承是指直接使用 基類的屬性和方法而無需額外編碼的能力;接口繼承是指僅使用屬性和方法的名稱、但是子類必須提供實現的能力。
多態
通過繼承實現的不同對象,調用相同的方法,產生不同的執行結果.。
五大基本原則:SPR, OCP, LSP, DIP, ISP
單一職責原則SRP(Single Responsibility Principle)
是指一個類的功能要單一,不能包羅萬象。如同一個人一樣,分配的工作不能太多,否則一天到晚雖然忙忙碌碌的,但效率卻高不起來。
開放封閉原則OCP(Open-Close Principle)
一個模塊在擴展性方面應該是開放的而在更改性方面應該是封閉的。
里式替換原則LSP(the Liskov Substitution Principle LSP)
子類應當可以替換父類並出現在父類能夠出現的任何地方。
依賴倒置原則DIP(the Dependency Inversion Principle DIP)
高層模塊不應該依賴低層模塊,二者都應該依賴其抽象。
接口分離原則ISP(the Interface Segregation Principle ISP)
模塊間要通過抽象接口隔離開,而不是通過具體的類強耦合起來
二十二、sqlserver的觸發器是什么?怎么使用觸發器?
觸發器是數據庫中由一定時間觸發的特殊的存儲過程,他不是由程序掉用也不是手工啟動的。觸發器的執行可以由對一個表的insert,delete, update等操作來觸發,觸發器經常用於加強數據的完整性約束和業務規則等等。
http://www.zyiz.net/tech/detail-182423.html
http://www.zyiz.net/tech/detail-182424.html
二十二、sqlserver里的面試題集合:
1. 索引的作用?和它的優點缺點是什么?
索引就一種特殊的查詢表,數據庫的搜索引擎可以利用它加速對數據的檢索。索引很類似與現實生活中書的目錄,不需要查詢整本書內容就可以找到想要的數據。缺點是它減慢了數據錄入的速度,同時也增加了數據庫的尺寸大小。
2. 介紹存儲過程基本概念和 她的優缺點
存儲過程是一個預編譯的SQL語句,他的優點是允許模塊化的設計,也就是說只需創建一次,在該程序中就可以調用多次。例如某次操作需要執行多次SQL,就可以把這個SQL做一個存儲過程,因為存儲過程是預編譯的,所以使用存儲過程比單純SQL語句執行要快。缺點是可移植性差,交互性差。
3. 使用索引有哪些需要注意的地方?
創建索引的的字段盡量小,最好是數值,比如整形int等;
對於頻繁修改的字段,盡量不要創建索引,維護索引的成本很高,而且更容易產生索引碎片;
定期的索引維護,如索引碎片的修復等;
不要建立或維護不必要的重復索引,會增加修改數據(新增、修改、刪除數據)的成本;
使用唯一性高的字段創建索引,切不可在性別這樣的低唯一性的字段上創建索引;
在SQL語句中,盡量不要在Where條件中使用函數、運算符或表達式計算,會造成索引無法正常使用;
應盡量避免在 where 子句中對字段進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表掃描;
應盡量避免在 where 子句中使用!=或<>操作符,否則將導致引擎放棄使用索引而進行全表掃描;
4. 索引碎片是如何產生的?有什么危害?又該如何處理?
索引在使用一段時間后(主要是新增、修改、刪除數據,如果該頁已經存儲滿了,就要進行頁的拆分,頻繁的拆分,會產生較多的索引碎片)會產生索引碎片。
索引碎片會嚴重印象數據的查詢效率,如果碎片太多,索引可能不會被使用。
碎片的處理方式主要有兩種:
第一種是預防:設置頁的填充因子
意思就是在頁上設置一段空白區域,在新增數據的時候,可以使用這段空白區域,可以一定的避免頁的拆分,從而減少索引碎片的產生。
填充因子就是用來描述這種頁中填充數據的一個比例,一般默認是100%填充的。如果我們修改填充因子為80%,那么頁在存儲數據時,就會剩余20%的剩余空間,這樣在下次插入的時候就不會拆分頁了。 那么是不是我們可以把填充因子設置低一點,留更多的剩余空間,不是很好嘛?當然也不好,填充因子設置的低,會需要分配更多的存儲空間,葉子節點的深度會增加,這樣是會影響查詢效率的,因此,這是要根據實際情況而定的。
那么一般我們是怎么設置填充因子的呢,主要根據表的讀寫比例而定的。如果讀的多,填充因子可以設置高一點,如100%,讀寫各一半,可以80~90%;修改多可以設置50~70%。
第二種是索引修復:定期對索引進行檢查、維護,寫一段SQL檢查索引的碎片比例,如果碎片過多,進行碎片修復或重建,定期執行即可。具體可以參考本文末尾的相關參考資料。
5. 鎖的目的是什么?
主要解決多個用戶同時對數據庫的並發操作時會帶來以下數據不一致的問題:
丟失更新,同時修改一條數據
讀臟,A修改了數據后,B讀取后A又取消了修改,B讀臟
不可重復讀,A用戶讀取數據,隨后B用戶讀取該數據並修改,此時A用戶再讀取數據時發現前后兩次的值不一致
還有一種是幻讀,這個情況好像不多。
並發控制的主要方法是封鎖,鎖就是在一段時間內禁止用戶做某些操作以避免產生數據不一致
6. 鎖的粒度有哪些?
數據庫鎖:鎖定整個數據庫,這通常發生在整個數據庫模式改變的時候。
表鎖:鎖定整個表,這包含了與該表相關聯的所有數據相關的對象,包括實際的數據行(每一行)以及與該表相關聯的所有索引中的鍵。
區段鎖:鎖定整個區段,因為一個區段由8頁組成,所以區段鎖定是指鎖定控制了區段、控制了該區段內8個數據或索引頁以及這8頁中的所有數據行。
頁鎖:鎖定該頁中的所有數據或索引鍵。
行或行標識符:雖然從技術上將,鎖是放在行標識符上的,但是本質上,它鎖定了整個數據行。
7. 什么是事務?什么是鎖?
事務就是被綁定在一起作為一個邏輯工作單元的SQL語句分組,如果任何一個語句操作失敗那么整個操作就被失敗,以后操作就會回滾到操作前狀態,或者是上個節點。為了確保要么執行,要么不執行,就可以使用事務。要將所有組語句作為事務考慮,就需要通過ACID測試,即原子性,一致性,隔離性和持久性。
鎖是實現事務的關鍵,鎖可以保證事務的完整性和並發性。
8. 視圖的作用,視圖可以更改么?
視圖是虛擬的表,與包含數據的表不一樣,視圖只包含使用時動態檢索數據的查詢;不包含任何列或數據。使用視圖可以簡化復雜的sql操作,隱藏具體的細節,保護數據;視圖創建后,可以使用與表相同的方式利用它們。
視圖的目的在於簡化檢索,保護數據,並不用於更新。
9. 什么是觸發器(trigger)? 觸發器有什么作用?
觸發器是數據庫中由一定時間觸發的特殊的存儲過程,他不是由程序掉用也不是手工啟動的。觸發器的執行可以由對一個表的insert,delete, update等操作來觸發,觸發器經常用於加強數據的完整性約束和業務規則等等。
10. SQL里面IN比較快還是EXISTS比較快?
這個題不能一概而論,要根據具體情況來看。IN適合於外表大而內表小的情況;EXISTS適合於外表小而內表大的情況。
如果查詢語句使用了not in,那么對內外表都進行全表掃描,沒有用到索引;而not exists的子查詢依然能用到表上的索引。所以無論哪個表大,用not exists都比not in 要快。參考資料:http://www.zyiz.net/tech/detail-182426.html
11. 維護數據庫的完整性和一致性,你喜歡用觸發器還是自寫業務邏輯?為什么?
盡可能使用約束,如check、主鍵、外鍵、非空字段等來約束。這樣做效率最高,也最方便。其次是使用觸發器,這種方法可以保證,無論什么業務系統訪問數據庫都可以保證數據的完整新和一致性。最后考慮的是自寫業務邏輯,但這樣做麻煩,編程復雜,效率低下。
二十三、oauth是什么?有哪些方式?
oauth是開發授權協議。主要用來頒發令牌(token)。有四種授權方式。
授權碼(authorization-code)
隱藏式(implicit)
密碼式(password):
客戶端憑證(client credentials)
1、授權碼(authorization code)方式,指的是第三方應用先申請一個授權碼,然后再用該碼獲取令牌。
這種方式是最常用的流程,安全性也最高,它適用於那些有后端的 Web 應用。授權碼通過前端傳送,令牌則是儲存在后端,而且所有與資源服務器的通信都在后端完成。這樣的前后端分離,可以避免令牌泄漏。
二十四、decimal的精度為什么比double高?
float 單精度浮點 32bit,
double 雙精度浮點64bit,
decimal是高精度 128bit,浮點型。
float double 是 基本類型(primitive type),decimal不是。
float 有效數字7位,范圍 ±1.5 × 10E−45 to ±3.4 × 10E38
double 有效數字15/16 位,范圍 ±5.0 × 10 E−324 to ±1.7 × 10E308
decimal 有效數字 28/29 位,范圍 ±1.0 × 10E−28 to ±7.9 × 10E28
decimal的有效位數很大,達到了28位,但是表示的數據范圍卻比float和double類型小。使用的時候會對計算時的性能有影響。
數值存儲范圍越小的精度越高,存儲數值范圍越大,精度就越不准確,如果存儲正常金額的情況下,使用money,好處在於可以存儲不指定的小數點位數的數值,比較真實。如果對於既要求精度,又固定小數點位數的數值存儲,采用decimal(numeric),優點在於可以自定義小數點位數,精度高。如特殊情況,如數值范圍巨大只能用float(real)類型了,此類型一般不提倡使用。