導航:首頁 > 編程語言 > java的內存gc

java的內存gc

發布時間:2023-01-05 05:32:41

java垃圾回收:GC在什麼時候對什麼做了什麼

GC在什麼時候對什麼做了什麼?
要回答這個問題,先了解下GC的發展史、jvm運行時數據區的劃分、jvm內存分配策略、jvm垃圾收集演算法等知識。
先說下jvm運行時數據的劃分,粗暴的分可以分為堆區(Heap)和棧區(Stack),但jvm的分法實際上比這復雜得多,大概分為下面幾塊:
1、程序計數器(Program Conuter Register)
程序計數器是一塊較小的內存空間,它是當前線程執行位元組碼的行號指示器,位元組碼解釋工作器就是通過改變這個計數器的值來選取下一條需要執行的指令。它是線程私有的內存,也是唯一一個沒有OOM異常的區域。
2、Java虛擬機棧區(Java Virtual Machine Stacks)
也就是通常所說的棧區,它描述的是Java方法執行的內存模型,每個方法被執行的時候都創建一個棧幀(Stack Frame),用於存儲局部變數表、操作數棧、動態鏈接、方法出口等。每個方法被調用到完成,相當於一個棧幀在虛擬機棧中從入棧到出棧的過程。此區域也是線程私有的內存,可能拋出兩種異常:如果線程請求的棧深度大於虛擬機允許的深度將拋出StackOverflowError;如果虛擬機棧可以動態的擴展,擴展到無法動態的申請到足夠的內存時會拋出OOM異常。
3、本地方法棧(Native Method Stacks)
本地方法棧與虛擬機棧發揮的作用非常相似,區別就是虛擬機棧為虛擬機執行Java方法,本地方法棧則是為虛擬機使用到的Native方法服務。
4、堆區(Heap)
所有對象實例和數組都在堆區上分配,堆區是GC主要管理的區域。堆區還可以細分為新生代、老年代,新生代還分為一個Eden區和兩個Survivor區。此塊內存為所有線程共享區域,當堆中沒有足夠內存完成實例分配時會拋出OOM異常。
5、方法區(Method Area)
方法區也是所有線程共享區,用於存儲已被虛擬機載入的類信息、常量、靜態變數、即時編譯後的代碼等數據。GC在這個區域很少出現,這個區域內存回收的目標主要是對常量池的回收和類型的卸載,回收的內存比較少,所以也有稱這個區域為永久代(Permanent Generation)的。當方法區無法滿足內存分配時拋出OOM異常。
6、運行時常量池(Runtime Constant Pool)
運行時常量池是方法區的一部分,用於存放編譯期生成的各種字面量和符號引用。

垃圾收集(Garbage Collection)並不是Java獨有的,最早是出現在Lisp語言中,它做的事就是自動管理內存,也就是下面三個問題:
1、什麼時候回收
2、哪些內存需要回收
3、如何回收

1、什麼時候回收?
上面說到GC經常發生的區域是堆區,堆區還可以細分為新生代、老年代,新生代還分為一個Eden區和兩個Survivor區。
1.1 對象優先在Eden中分配,當Eden中沒有足夠空間時,虛擬機將發生一次Minor GC,因為Java大多數對象都是朝生夕滅,所以Minor GC非常頻繁,而且速度也很快;
1.2 Full GC,發生在老年代的GC,當老年代沒有足夠的空間時即發生Full GC,發生Full GC一般都會有一次Minor GC。大對象直接進入老年代,如很長的字元串數組,虛擬機提供一個-XX:PretenureSizeThreadhold參數,令大於這個參數值的對象直接在老年代中分配,避免在Eden區和兩個Survivor區發生大量的內存拷貝;
1.3 發生Minor GC時,虛擬機會檢測之前每次晉升到老年代的平均大小是否大於老年代的剩餘空間大小,如果大於,則進行一次Full GC,如果小於,則查看HandlePromotionFailure設置是否允許擔保失敗,如果允許,那隻會進行一次Minor GC,如果不允許,則改為進行一次Full GC。

2、哪些內存需要回收
jvm對不可用的對象進行回收,哪些對象是可用的,哪些是不可用的?Java並不是採用引用計數演算法來判定對象是否可用,而是採用根搜索演算法(GC Root Tracing),當一個對象到GC Roots沒有任何引用相連接,用圖論的來說就是從GC Roots到這個對象不可達,則證明此對象是不可用的,說明此對象可以被GC。對於這些不可達對象,也不是一下子就被GC,而是至少要經歷兩次標記過程:如果對象在進行根搜索演算法後發現沒有與GC Roots相連接的引用鏈,那它將會第一次標記並且進行一次篩選,篩選條件是此對象有沒有必要執行finalize()方法,當對象沒有覆蓋finalize()方法或者finalize()方法已經被虛擬機調用執行過一次,這兩種情況都被視為沒有必要執行finalize()方法,對於沒有必要執行finalize()方法的將會被GC,對於有必要有必要執行的,對象在finalize()方法中可能會自救,也就是重新與引用鏈上的任何一個對象建立關聯即可。

3、如何回收
選擇不同的垃圾收集器,所使用的收集演算法也不同。
在新生代中,每次垃圾收集都發現有大批對象死去,只有少量存活,則使用復制演算法,新生代內存被分為一個較大的Eden區和兩個較小的Survivor區,每次只使用Eden區和一個Survivor區,當回收時將Eden區和Survivor還存活著的對象一次性的拷貝到另一個Survivor區上,最後清理掉Eden區和剛才使用過的Survivor區,Eden和Survivor的默認比例是8:1,可以使用-XX:SurvivorRatio來設置該比例。
而老年代中對象存活率高,沒有額外的空間對它進行分配擔保,必須使用「標記-清理」或「標記-整理」演算法。

⑵ java中GC指的是什麼

gc是指垃圾回收機制,當一個對象不能再被後續程序所引用到時,這個對象所佔用的內存空間就沒有存在的意義了,java虛擬機會不定時的去檢測內存中這樣的對象,然後回收這塊內存空間。

⑶ Java 等語言的 GC 為什麼不及時釋放內存

c語言沒有垃圾回收機制,所有new出來的內存都要手動釋放,優點是效率高,
一旦free立即執行,缺點是手動釋放xd.
java有獨立的gc線程,
而且由於gc線程執行優先順序很低,垃圾能不能及時回收取
決於gc策略和工作線程的執行密度.

⑷ Java系統中GC頻繁啟動是什麼原因

GC頻繁發生的原因是堆空間不足。
修改permanent的大小是解決不了問題的,一般來說,permanent(持久帶)的變化並不大,如果持久帶不夠用,一般不會GC,而是直接拋出持久帶的OOM( out of memory)
所以,解決該公司的問題,最重要的是提高最小堆空間-Xms和最大堆空間-Xmx 的大小,提高年輕帶-Xmn有助於在一定的程度解決GC的問題,但是注意,這些只是很簡單的討論。個人覺得,頻繁GC發生的問題,最好是看看內存的DUMP文件,進行分析,在對JVM參數進行相對的配置。
JVM相關的問題還是比較復雜的,並不是幾句對參數的描述就能解決問題,你還是要多看JVM相關資料。
評論(0)

⑸ 深入理解 Java 之 GC 到底如何工作

GarbageCollection簡稱為GC,是垃圾回收的意思、內存處理器是編程人員容易出現問題的地方,忘記或者錯誤的內存回收會導致程序或系統的不穩定甚至崩潰。Java語言提供的GC功能可以自動的檢測對象是否超過作用域,從而達到自動回收內存的目的,java語言沒有提供釋放已分配內存的顯示操作方法,資源回收工作全部交由GC來完成,程序員不能精確的控制垃圾回收的時機。

GC在實現垃圾回收時的基本原理:

Java的內存管理實際就是對象的管理,其中包括對像的分配和釋放。對於程序員來說,分配對象使用new關鍵字,釋放對象時只是將對象賦值為null,讓程序員不能夠再訪問到這個對象,該對象被稱為「不可達」。GC將負責回收所有「不可達」對象的內存空間。

對於GC來說,當程序員創建對象時,GC就開始監控這個對象地址、大小以及使用情況。通常GC採用有向圖的方式記錄並管理堆中的所有對象,通過這種方式確定哪些對象是「可達」的,哪些對象是「不可達」的。當GC確定一些對象為「不可達時」GC就有責任回收這些內存空間,但為了GC能夠在不同的平台上實現,java規范對GC的很多行為都沒有進行嚴格的規定。例如對於採用什麼類型的回收演算法、什麼時候進行回收等重要問題都沒有明確的規定,因此不同的JVM實現著不同的的實現演算法,這也給JAVA程序員的開發帶來了很多不確定性。

⑹ Java中 gc的作用是什麼

System.gc()用來強制立即回收垃圾,即釋放內存。
java對內存的釋放採取的垃圾自動回收機制,在編程的時候不用考慮變數不用時釋放內存,java虛擬機可以自動判斷出並收集到垃圾,但一般不會立即釋放它們的內存空間,當然也可以在程序中使用System.gc()來強制垃圾回收,但是要注意的是,系統並不保證會立即進行釋放內存

⑺ IBM Java如何做到高性能GC的實現內幕

IBM JVM的GC分為三個步驟 Mark phase(標記) Sweep phase(清掃) Compaction phase(內存緊縮) 在了解這些過程之前 我們先看一下IBMJava中的對象的Layout和Heap lay out 一個Java對象在IBM vm中的結構如下 size+flags mptr locknflags objectdata size+flags 這是一個 byte的slot( 平台) 這個slot的主要功能就是描述對象的尺寸 由於IBMJava中的對象都是以 byte的倍數分配的 因此對象的尺寸其實就是真實尺寸/ 存放在 byte的slot中 另外在這個slot的低三位是保留欄位起到標記對象的作用 他們分別為 bit :swapped bit 這個交換位被用於Compaction phase即內存緊縮階段使用 同時 這一位在標記堆棧溢出的時候(mark stack overflow)也被用於標記NotYetScanned狀態 bit dosed bit 這個位用於標示這個對象是否被某個堆棧或者寄存器reference到了 如果這個標志被至位則這個對象就不能在當前的GC cycle中被刪除 而且如果某個reference指向的內存不是一個真實的reference比如是一個簡單的float 或者integer變數但是它的值恰巧就是Heap中某個Object的地址的時候 我們就不能修改這個refernece 這種對象的bit 也被置為 bit :pinned bit 標記一個對象是否是一個一個釘扣對象(PINNED object) 一個Pinned Object也不能被GC刪除 因為他們可能在Heap之外被reference到了 典型的一個例子就是Thread 還記得我上面說的僵死縣城么?它不能被刪除的道理就是這個 另外一種PinnedObject就是 JNI Object 即被本地代碼使用的對象 Mptr: 在 平台上也是 byte的slot Mptr有兩個功能 如果mptr不是一個數組 則Mptr指向一個方法塊(method block) 你可以通過這個method block來得到一個類塊(class block) 這個類塊 告訴你這個Object是屬於哪個class的實例 method block和class block由Class Loader分配 而不是heap在heap中進行分配 如果mptr是一個數組(Array) mptr包含了這個對象中 數組的元素個數 lockflags 在 平台上也是 byte的slot 但是這個slot只有低 位被用到 bit :是array flag 如果這個位被置位 那麼這個對象就是一個數組同時mptr欄位就包含了數組的元素個數 bit 是hashed和moved bit 如果這個位被置位 那麼他就告訴我們這個對象在被hashed以後被刪除了 Object Data 就是這個對象本身的數據 Heap layout: heap top heap limit heap base heap base是heap的起始地址 heap top是heap的結束地址 heaplimit 是當前程序使用的那段heap可以進行擴展和收縮的極限 你可以用 Xmx參數在java運行的時候對heap top和heap base進行控制 Alloc bits 和 mark bits heap top allocmax markemax heap limit alloc size marksize heap base 上面這個結構描述了heap和alloc bits 以及 markbits之間的關系 allocbits和markbits都是元素為 個bit的vector 他們與heap有同樣的長度 下面是兩個對象被分配以後在heap和兩個vector中的表現 heaptop allocmax markmax heaplimit allocsize marksize object top object base object allocbit object markbit object top object base object allocbit 如上面的結構 如果一個對象在heap被alloc出來 那麼在allocbits中就標示出這個對象的起始地址所在的地址 allocbits中只標記起始地址 但是這個過程告訴我們這個對象在那裡被創建 但是不告訴我們這個對象是否存活 當在mark phase中如果某一個對象比如object 仍然存活 那麼就在markbits中對應的地址上標記一下The free list IBM jvm中的空閑塊用用一個free list鏈標示 如圖 freechunck freechunck freechunckn size size size next >next > next >NULL freeStorage freeStorage freeste 有了這些基本概念我們來看看Mark phase的工作情況 MarkPhase GC的Mark phase將標記所有還活著的對象 這個標記所有可達對象的過程稱為tracing Jvm的活動狀態(active state)是由下面幾個部分組成的 每個線程的保存寄存器(saved registers) 描述線程的堆棧 Java類中的靜態元素 以及局部和全局的JNI(Java Native Interface)引用 在Jvm中的方法調用都在C Stack上引發一個Frame 這個Frame包含了 對象實例 為局部變數的assignment結果或者傳入方法的參數 所有這些引用在Tracing過程中都被同等對待 實際上 我們可以把一個線程的堆棧看城一系列 bytes slot的集合 然後對每一個堆棧都從頂向下對這些slot進行掃描 在掃描的過程中都必須校驗每個slot是否指向heap當中的一個真實的對象 因為在前面我就說過 很有可能這些slot值僅僅是一個int或float但是他們的值恰巧就等於heap中的一個對象地址 因此在掃描的時候必須相當的保守 掃描的時候必須保證所有的指針都是一個對象 而且這個對象沒有在GC中被刪除 只有符合下面條件的slot才是一個指向對象的指針 必須以 byte的倍數分配的內存 必須在heap的范圍之內(即大於heapbase小於heaptop) 對應的allocbit必須置為 滿足這些條件的對象引用我們稱為roots 並且把他們的dosed bit置為 表示不能被GC刪除 我想大家已經知道C#中為何連Int和Float都是OBject的原因了吧 在C#中因為都是OBject因此 在tracing的過程中就減少了一次校驗 這個減少對性能起到很大的影響 如果掃描完成 那麼Tracing過程便能安全精確的執行 也就是說我們可以在roots中通過reference找到他對應的objects 由於他們是真實的reference 那麼我們就能夠在pactionphase中移動對應的對象並且修改這些reference Trace過程使用了一個可以容納 k的slots的stack 所有的引用逐個push進入這個堆棧並且同時在markbits中進行標記 當push和mark的工作完成之後 我們開始pop出這些slot並且進行trace 常規的對象(非數組對象)將通過mptr去訪問clas *** lock clas *** lock將會告訴我們從這個對象中找到的其他對象的reference在那裡?當我們在clas *** lock找到一個refernce以後 如果發現他沒有被mark 那麼我們就在markallocbits中mark他然後把他再壓入堆棧 數組對象利用mptr去訪問每個數組元素 如果他們沒有mark則mark然後壓入堆棧 Trace過程一直持續進行 直到堆棧為空 MarkStack OverFlow 由於markStack限制了尺寸 因此它可能會溢出 如果溢出發生 那麼我們就設定一個全局的標志來表明發生了MarkStack OverFlow 然後我們將那些不能push入stack的OBject的bit 設定為NotYetScanned 然後當tracing過程完成以後 檢驗全局標志如果發現有overflow則把NotYetScanned的對象再次壓入堆棧開始新的tracing過程 並行Mark(Parallel Mark) 由於使用逐位清掃(biise sweep)和內存緊縮規避功能 GC將化大部分的時間是用於Mark而非前面兩項 這就導致了IBM JVM需要開發一個GC的並行版本 並行GC的目的不是以犧牲單CPU系統上的效能來換取在 路對稱CPU系統上的高效率 並行Mark的基本思想就是通過多個輔助線程(helper thread)和一個共享工作的工具來減少Marking的時間 在單CPU系統中 執行GC工作的只有一個主線程 Parallel mark仍然需要這個主線程的參與 他充當了管理協調的角色 這個Thread所要執行的工作和單CPU上的一樣多 包括他必須掃描C Stack來鑒別需要收集的roots指針 一個有N路對稱CPU的系統自動含有n 個helper thread並且平均分布在每個CPU上 master thread將scan完的reference集合進行分塊 然後交給helper thread獨立完成mark工作 每個Helper thread都被分配了一個獨立的本地mark stack 以及一個shareable queue sharqueue將存放help thread在mark overflow的時候的NotyetScanned對象 然後由master thread將sharequeue中的對象balance到其他已經空閑的thread上去 並發Mark(Concurrent mark) Concurrent mark的主要目的在於當heap增長的時候減少GC的pause time 只要heap到達heap limit的時候 Concurrent mark就會被執行 在Concurrent phase中 GC要求應用中的每個線程(不是指helper thread而是應用程序自己開啟的線程以便充分利用系統資源)掃描他們自己的堆棧來得到roots 然後使用這些roots來同步的trace 可達對象 Tracing工作是由一個後台的低優先順序的線程執行 同時程序自己開啟的線程在分配內存的時候必須執行heap lock allocation 由於使用程序自己開啟的線程並發的執行mark live objects 我們必須紀錄那些已經trace過的object的變化 這個功能是採用一個叫寫閘(write barrier) 來實現的 這個寫閘在每次改變引用的時候被激活 它告訴我們什麼時候一個對象被跟新過了 以便我們從新掃描那部分heap 寫閘的具體實現是Heap會分配出 byte的內存段每個段都分配了一個byte在卡表中(card table) 無論何時一個對象的reference被更新cardtable將同步紀錄這個對象的起始地址 使用Byte而不用bit的原因是寫byte要比寫bit快 倍 而且我們可能希望空餘的bit會在未來被用到 當Concurrent mark執行完畢以後 S collection(stop total world)將會被執行 s的意思是指suspend所有程序自己開啟的線程 因此我們可以看到如果使用Concurrent mark那 lishixin/Article/program/Java/JSP/201311/19555

⑻ java中GC是什麼為什麼要有GC

gc是指垃圾回收機制,當一個對象不能再被後續程序所引用到時,這個對象所佔用的內存空間就沒有存在的意義了,java虛擬機會不定時的去檢測內存中這樣的對象,然後回收這塊內存空間。

⑼ GC是什麼GC的作用有了GC那java中還有內存泄露么求解答

它擯棄了C++中一些繁瑣容易出錯的東西。其中有一條就是這個GC。 寫C/C++程序,程序員定義了一個變數,就是在內存中開辟了一段相應的空間來存值。內存再大也是有限的,所以當程序不再需要使用某個變數的時候,就需要釋放這個內存空間資源,好讓別的變數來用它。在C/C++中,釋放無用變數內存空間的事情要由程序員自己來解決。就是說當程序員認為變數沒用了,就應當寫一條代碼,釋放它佔用的內存。這樣才能最大程度地避免內存泄露和資源浪費。但是這樣顯然是非常繁瑣的。程序比較大,變數多的時候往往程序員就忘記釋放內存或者在不該釋放的時候釋放內存了。而且釋放內存這種事情,從開發角度說,不應當是程序員所應當關注的。程序員所要做的應該是實現所需要的程序功能,而不是耗費大量精力在內存的分配釋放上。 Java有了GC,就不需要程序員去人工釋放內存空間。當Java虛擬機發覺內存資源緊張的時候,就會自動地去清理無用變數所佔用的內存空間。當然,如果需要,程序員可以在Java程序中顯式地使用System.gc()來強制進行一次立即的內存清理。但是要注意的是,系統並不保證會立即進行釋放內存。Java的內存泄漏問題Java的一個重要優點就是通過垃圾收集器(Garbage Collection,GC)自動管理內存的回收,程序員不需要通過調用函數來釋放內存。因此,很多程序員認為Java不存在內存泄漏問題,或者認為即使有內存泄漏也不是程序的責任,而是GC或JVM的問題。其實,這種想法是不正確的,因為Java也存在內存泄露,但它的表現與C++不同。隨著越來越多的伺服器程序採用Java技術,例如JSP,Servlet, EJB等,伺服器程序往往長期運行。另外,在很多嵌入式系統中,內存的總量非常有限。內存泄露問題也就變得十分關鍵,即使每次運行少量泄漏,長期運行之後,系統也是面臨崩潰的危險。什麼是內存泄漏?在Java中,內存泄漏就是存在一些被分配的對象,這些對象有下面兩個特點,首先,這些對象是可達的,即在有向圖中,存在通路可以與其相連;其次,這些對象是無用的,即程序以後不會再使用這些對象。如果對象滿足這兩個條件,這些對象就可以判定為Java中的內存泄漏,這些對象不會被GC所回收,然而它卻佔用內存。在C++中,內存泄漏的范圍更大一些。有些對象被分配了內存空間,然後卻不可達,由於C++中沒有GC,這些內存將永遠收不回來。在Java中,這些不可達的對象都由GC負責回收,因此程序員不需要考慮這部分的內存泄露。通過分析,我們得知,對於C++,程序員需要自己管理邊和頂點,而對於Java程序員只需要管理邊就可以了(不需要管理頂點的釋放)。通過這種方式,Java提高了編程的效率。
因此,通過以上分析,我們知道在Java中也有內存泄漏,但范圍比C++要小一些。因為Java從語言上保證,任何對象都是可達的,所有的不可達對象都由GC管理。下面給出了一個簡單的內存泄露的例子:在這個例子中,我們循環申請Object對象,並將所申請的對象放入一個Vector中,如果我們僅僅釋放引用本身,那麼Vector仍然引用該對象,所以這個對象對GC來說是不可回收的。因此,如果對象加入到Vector後,還必須從Vector中刪除,最簡單的方法就是將Vector對象設置為null。Vector v=new Vector(10); for (int i=1;i<100; i++) { Object o=new Object(); v.add(o); o=null; }
//此時,所有的Object對象都沒有被釋放,因為變數v引用這些對象。 綜上所述,Java也存在內存泄露問題,其原因主要是一些對象雖然不再被使用,但它們仍然被引用。為了解決這些問題,我們可以通過軟體工具來檢查內存泄露,檢查的主要原理就是暴露出所有堆中的對象,讓程序員尋找那些無用但仍被引用的對象。

⑽ Java垃圾回收:GC在什麼時候對什麼做了什麼

1、首先,GC又分為minor GC 和 Full GC(major GC)。Java堆內存分為新生代和老年代,新生代中又分為1個eden區和兩個Survior區域。

2、一般情況下,新創建的對象都會被分配到eden區,這些對象經過一個minor gc後仍然存活將會被移動到Survior區域中,對象在Survior中沒熬過一個Minor GC,年齡就會增加一歲,當他的年齡到達一定程度時,就會被移動到老年代中。

3、當eden區滿時,還存活的對象將被復制到survior區,當一個survior區滿時,此區域的存活對象將被復制到另外一個survior區,當另外一個也滿了的時候,從前一個Survior區復制過來的並且此時還存活的對象,將可能被復制到老年代。因為年輕代中的對象基本都是朝生夕死(80%以上),所以年輕代的垃圾回收演算法使用的是復制演算法,復制演算法的基本思想是將內存分為兩塊,每次只有其中一塊,當這一塊內存使用完,就將還活著的對象復制到另一塊上面。復制演算法不會產生內存碎片。

4、在GC開始的時候,對象只會存在於eden區,和名為「From」的Survior區,Survior區「to」是空的。緊接著GCeden區中所有存活的對象都會被復制到「To」,而在from區中,仍存活的對象會根據他們的年齡值來決定去向,年齡到達一定只的對象會被復制到老年代,沒有到達的對象會被復制到to survior中,經過這次gc後,eden區和fromsurvior區已經被清空。這個時候,from和to會交換他們的角色,也就是新的to就是上次GC前的fromMinor GC:從年輕代回收內存。

5、當jvm無法為一個新的對象分配空間時會觸發Minor GC,比如當Eden區滿了。當內存池被填滿的時候,其中的內容全部會被復制,指針會從0開始跟蹤空閑內存。Eden和Survior區不存在內存碎片寫指針總是停留在所使用內存池的頂部。執行minor操作時不會影響到永久代,從永久帶到年輕代的引用被當成GC roots,從年輕代到永久代的引用在標記階段被直接忽略掉(永久代用來存放java的類信息)。如果eden區域中大部分對象被認為是垃圾,永遠也不會復制到Survior區域或者老年代空間。如果正好相反,eden區域大部分新生對象不符合GC條件,Minor GC執行時暫停的線程時間將會長很多。Minor may call "stop the world"。

閱讀全文

與java的內存gc相關的資料

熱點內容
dvd光碟存儲漢子演算法 瀏覽:755
蘋果郵件無法連接伺服器地址 瀏覽:960
phpffmpeg轉碼 瀏覽:669
長沙好玩的解壓項目 瀏覽:141
專屬學情分析報告是什麼app 瀏覽:563
php工程部署 瀏覽:831
android全屏透明 瀏覽:730
阿里雲伺服器已開通怎麼辦 瀏覽:801
光遇為什麼登錄時伺服器已滿 瀏覽:301
PDF分析 瀏覽:484
h3c光纖全工半全工設置命令 瀏覽:141
公司法pdf下載 瀏覽:381
linuxmarkdown 瀏覽:350
華為手機怎麼多選文件夾 瀏覽:683
如何取消命令方塊指令 瀏覽:349
風翼app為什麼進不去了 瀏覽:778
im4java壓縮圖片 瀏覽:362
數據查詢網站源碼 瀏覽:150
伊克塞爾文檔怎麼進行加密 瀏覽:890
app轉賬是什麼 瀏覽:163