您好,登錄后才能下訂單哦!
這篇文章主要介紹“JVM垃圾回收基本原理是什么”,在日常操作中,相信很多人在JVM垃圾回收基本原理是什么問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”JVM垃圾回收基本原理是什么”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
Java的內存分配與回收全部由JVM垃圾回收進程自動完成。與C語言不同,Java開發者不需要自己編寫代碼實現垃圾回收。這是Java深受大家歡迎的眾多特性之一,能夠幫助程序員更好地編寫Java程序。
JavaAPI:一系列幫助開發者創建Java應用程序的封裝好的庫。
Java 開發工具包 (JDK):一系列工具幫助開發者創建Java應用程序。JDK包含工具編譯、運行、打包、分發和監視Java應用程序。
Java 虛擬機(JVM):JVM是一個抽象的計算機結構。Java程序根據JVM的特性編寫。JVM針對特定于操作系統并且可以將Java指令翻譯成底層系統的指令并執行。JVM確保了Java的平臺無關性。
Java 運行環境(JRE):JRE包含JVM實現和Java API。
每種JVM實現可能采用不同的方法實現垃圾回收機制。在收購SUN之前,Oracle使用的是JRockit JVM,收購之后使用HotSpot JVM。目前Oracle擁有兩種JVM實現并且一段時間后兩個JVM實現會合二為一。
HotSpot JVM是目前Oracle SE平臺標準核心組件的一部分。在這篇垃圾回收教程中,我們將會了解基于HotSpot虛擬機的垃圾回收原則。
我們有必要了解堆內存在JVM內存模型的角色。在運行時,Java的實例被存放在堆內存區域。當一個對象不再被引用時,滿足條件就會從堆內存移除。在垃圾回收進程中,這些對象將會從堆內存移除并且內存空間被回收。堆內存以下三個主要區域:
新生代(Young Generation)
Eden空間(Eden space,任何實例都通過Eden空間進入運行時內存區域)
S0 Survivor空間(S0 Survivor space,存在時間長的實例將會從Eden空間移動到S0 Survivor空間)
S1 Survivor空間 (存在時間更長的實例將會從S0 Survivor空間移動到S1 Survivor空間)
老年代(Old Generation)實例將從S1提升到Tenured(終身代)
永久代(Permanent Generation)包含類、方法等細節的元信息
永久代空間 在Java SE8特性中已經被移除。
Java 垃圾回收是一項自動化的過程,用來管理程序所使用的運行時內存。通過這一自動化過程,JVM 解除了程序員在程序中分配和釋放內存資源的開銷。
作為一個自動的過程,程序員不需要在代碼中顯示地啟動垃圾回收過程。System.gc()
和Runtime.gc()
用來請求JVM啟動垃圾回收。
雖然這個請求機制提供給程序員一個啟動 GC 過程的機會,但是啟動由 JVM負責。JVM可以拒絕這個請求,所以并不保證這些調用都將執行垃圾回收。啟動時機的選擇由JVM決定,并且取決于堆內存中Eden區是否可用。JVM將這個選擇留給了Java規范的實現,不同實現具體使用的算法不盡相同。
毋庸置疑,我們知道垃圾回收過程是不能被強制執行的。我剛剛發現了一個調用System.gc()
有意義的場景。通過這篇文章了解一下
適合調用System.gc() 這種極端情況。
說到GC類型,就更有意思了,為什么呢,因為業界沒有統一的嚴格意義上的界限,也沒有嚴格意義上的GC類型,都是左邊一個教授一套名字,右邊一個作者一套名字。為什么會有這個情況呢,因為GC類型是和收集器有關的,不同的收集器會有自己獨特的一些收集類型。所以作者在這里引用R大關于GC類型的介紹,作者覺得還是比較妥當準確的。如下:
Partial GC:并不收集整個GC堆的模式
Young GC(Minor GC):只收集young gen的GC
Old GC:只收集old gen的GC。只有CMS的concurrent collection是這個模式
Mixed GC:收集整個young gen以及部分old gen的GC。只有G1有這個模式
Full GC(Major GC):收集整個堆,包括young gen、old gen、perm gen(如果存在的話)等所有部分的模式。
上面大家也看到了,GC類型分分類是和收集器有關的,那么當然了,對于不同的收集器,GC觸發時機也是不一樣的,作者就針對默認的serial GC來說:
young GC:當young gen中的eden區分配滿的時候觸發。注意young GC中有部分存活對象會晉升到old gen,所以young GC后old gen的占用量通常會有所升高。
full GC:當準備要觸發一次young GC時,如果發現統計數據說之前young GC的平均晉升大小比目前old gen剩余的空間大,則不會觸發young GC而是轉為觸發full GC(因為HotSpot VM的GC里,除了CMS的concurrent collection之外,其它能收集old gen的GC都會同時收集整個GC堆,包括young gen,所以不需要事先觸發一次單獨的young GC);或者,如果有perm gen的話,要在perm gen分配空間但已經沒有足夠空間時,也要觸發一次full GC;或者System.gc()、heap dump帶GC,默認也是觸發full GC。
除直接調用System.gc外,觸發Full GC執行的情況有如下四種。
舊生代空間不足
舊生代空間只有在新生代對象轉入及創建為大對象、大數組時才會出現不足的現象,當執行Full GC后空間仍然不足,則拋出如下錯誤:
java.lang.OutOfMemoryError: Java heap space
為避免以上兩種狀況引起的Full GC,調優時應盡量做到讓對象在Minor GC階段被回收、讓對象在新生代多存活一段時間及不要創建過大的對象及數組。
2. Permanet Generation空間滿
Permanet Generation中存放的為一些class的信息等,當系統中要加載的類、反射的類和調用的方法較多時,Permanet Generation可能會被占滿,在未配置為采用CMS GC的情況下會執行Full GC。如果經過Full GC仍然回收不了,那么JVM會拋出如下錯誤信息:
java.lang.OutOfMemoryError: PermGen space
為避免Perm Gen占滿造成Full GC現象,可采用的方法為增大Perm Gen空間或轉為使用CMS GC。
3. CMS GC時出現promotion failed和concurrent mode failure
對于采用CMS進行舊生代GC的程序而言,尤其要注意GC日志中是否有promotion failed和concurrent mode failure兩種狀況,當這兩種狀況出現時可能會觸發Full GC。
promotion failed是在進行Minor GC時,survivor space放不下、對象只能放入舊生代,而此時舊生代也放不下造成的;concurrent mode failure是在執行CMS GC的過程中同時有對象要放入舊生代,而此時舊生代空間不足造成的。
應對措施為:增大survivor space、舊生代空間或調低觸發并發GC的比率,但在JDK 5.0+、6.0+的版本中有可能會由于JDK的bug29導致CMS在remark完畢后很久才觸發sweeping動作。對于這種狀況,可通過設置-XX: CMSMaxAbortablePrecleanTime=5(單位為ms)來避免。
統計得到的Minor GC晉升到舊生代的平均大小大于舊生代的剩余空間
這是一個較為復雜的觸發情況,Hotspot為了避免由于新生代對象晉升到舊生代導致舊生代空間不足的現象,在進行Minor GC時,做了一個判斷,如果之前統計所得到的Minor GC晉升到舊生代的平均大小大于舊生代的剩余空間,那么就直接觸發Full GC。
例如程序第一次觸發Minor GC后,有6MB的對象晉升到舊生代,那么當下一次Minor GC發生時,首先檢查舊生代的剩余空間是否大于6MB,如果小于6MB,則執行Full GC。
當新生代采用PS GC時,方式稍有不同,PS GC是在Minor GC后也會檢查,例如上面的例子中第一次Minor GC后,PS GC會檢查此時舊生代的剩余空間是否大于6MB,如小于,則觸發對舊生代的回收。
除了以上4種狀況外,對于使用RMI來進行RPC或管理的Sun JDK應用而言,默認情況下會一小時執行一次Full GC。可通過在啟動時通過- java -Dsun.rmi.dgc.client.gcInterval=3600000來設置Full GC執行的間隔時間或通過-XX:+ DisableExplicitGC來禁止RMI調用System.gc。
Minor GC ,Full GC 觸發條件
Minor GC觸發條件:當Eden區滿時,觸發Minor GC。
Full GC觸發條件:
(1)調用System.gc時,系統建議執行Full GC,但是不必然執行
(2)老年代空間不足
(3)方法去空間不足
(4)通過Minor GC后進入老年代的平均大小大于老年代的可用內存
(5)由Eden區、From Space區向To Space區復制時,對象大小大于To Space可用內存,則把該對象轉存到老年代,且老年代的可用內存小于該對象大小
Java中Stop-The-World機制簡稱STW,是在執行垃圾收集算法時,Java應用程序的其他所有線程都被掛起(除了垃圾收集幫助器之外)。Java中一種全局暫停現象,全局停頓,所有Java代碼停止,native代碼可以執行,但不能與JVM交互;這些現象多半是由于gc引起。
GC時的Stop the World(STW)是大家最大的敵人。但可能很多人還不清楚,除了GC,JVM下還會發生停頓現象。
JVM里有一條特殊的線程--VM Threads,專門用來執行一些特殊的VM Operation,比如分派GC,thread dump等,這些任務,都需要整個Heap,以及所有線程的狀態是靜止的,一致的才能進行。所以JVM引入了安全點(Safe Point)的概念,想辦法在需要進行VM Operation時,通知所有的線程進入一個靜止的安全點。
除了GC,其他觸發安全點的VM Operation包括:
1. JIT相關,比如Code deoptimization, Flushing code cache ;
2. Class redefinition (e.g. javaagent,AOP代碼植入的產生的instrumentation) ;
3. Biased lock revocation 取消偏向鎖 ;
4. Various debug operation (e.g. thread dump or deadlock check);
垃圾回收是一種回收無用內存空間并使其對未來實例可用的過程。
Eden 區:當一個實例被創建了,首先會被存儲在堆內存年輕代的 Eden 區中。
注意:如果你不能理解這些詞匯,我建議你閱讀這篇 垃圾回收介紹 ,這篇教程詳細地介紹了內存模型、JVM 架構以及這些術語。
Survivor 區(S0 和 S1):作為年輕代 GC(Minor GC)周期的一部分,存活的對象(仍然被引用的)從 Eden 區被移動到 Survivor 區的 S0 中。類似的,垃圾回收器會掃描 S0 然后將存活的實例移動到 S1 中。
(譯注:此處不應該是Eden和S0中存活的都移到S1么,為什么會先移到S0再從S0移到S1?)
死亡的實例(不再被引用)被標記為垃圾回收。根據垃圾回收器(有四種常用的垃圾回收器,將在下一教程中介紹它們)選擇的不同,要么被標記的實例都會不停地從內存中移除,要么回收過程會在一個單獨的進程中完成。
老年代: 老年代(Old or tenured generation)是堆內存中的第二塊邏輯區。當垃圾回收器執行 Minor GC 周期時,在 S1 Survivor 區中的存活實例將會被晉升到老年代,而未被引用的對象被標記為回收。
老年代 GC(Major GC):相對于 Java 垃圾回收過程,老年代是實例生命周期的最后階段。Major GC 掃描老年代的垃圾回收過程。如果實例不再被引用,那么它們會被標記為回收,否則它們會繼續留在老年代中。
內存碎片:一旦實例從堆內存中被刪除,其位置就會變空并且可用于未來實例的分配。這些空出的空間將會使整個內存區域碎片化。為了實例的快速分配,需要進行碎片整理。基于垃圾回收器的不同選擇,回收的內存區域要么被不停地被整理,要么在一個單獨的GC進程中完成。
在釋放一個實例和回收內存空間之前,Java 垃圾回收器會調用實例各自的
finalize()
方法,從而該實例有機會釋放所持有的資源。雖然可以保證
finalize()
會在回收內存空間之前被調用,但是沒有指定的順序和時間。多個實例間的順序是無法被預知,甚至可能會并行發生。程序不應該預先調整實例之間的順序并使用
finalize()
方法回收資源。
任何在 finalize過程中未被捕獲的異常會自動被忽略,然后該實例的 finalize 過程被取消。
JVM 規范中并沒有討論關于弱引用的垃圾回收機制,也沒有很明確的要求。具體的實現都由實現方決定。
垃圾回收是由一個守護線程完成的。
所有實例都沒有活動線程訪問。
沒有被其他任何實例訪問的循環引用實例。
Java 中有不同的引用類型。判斷實例是否符合垃圾收集的條件都依賴于它的引用類型。
引用類型 | 垃圾收集 |
---|---|
強引用(Strong Reference) | 不符合垃圾收集 |
軟引用(Soft Reference) | 垃圾收集可能會執行,但會作為最后的選擇 |
弱引用(Weak Reference) | 符合垃圾收集 |
虛引用(Phantom Reference) | 符合垃圾收集 |
在編譯過程中作為一種優化技術,Java 編譯器能選擇給實例賦
null
值,從而標記實例為可回收。
class Animal { public static void main(String[] args) { Animal lion = new Animal(); System.out.println("Main is completed."); } protected void finalize() { System.out.println("Rest in Peace!"); } }
在上面的類中,lion
對象在實例化行后從未被使用過。因此 Java 編譯器作為一種優化措施可以直接在實例化行后賦值lion = null
。因此,即使在 SOP 輸出之前, finalize 函數也能夠打印出
'Rest in Peace!'
。我們不能證明這確定會發生,因為它依賴JVM的實現方式和運行時使用的內存。然而,我們還能學習到一點:如果編譯器看到該實例在未來再也不會被引用,能夠選擇并提早釋放實例空間。
關于對象什么時候符合垃圾回收有一個更好的例子。實例的所有屬性能被存儲在寄存器中,隨后寄存器將被訪問并讀取內容。無一例外,這些值將被寫回到實例中。雖然這些值在將來能被使用,這個實例仍然能被標記為符合垃圾回收。這是一個很經典的例子,不是嗎?
當被賦值為null時,這是很簡單的一個符合垃圾回收的示例。當然,復雜的情況可以像上面的幾點。這是由 JVM 實現者所做的選擇。目的是留下盡可能小的內存占用,加快響應速度,提高吞吐量。為了實現這一目標, JVM 的實現者可以選擇一個更好的方案或算法在垃圾回收過程中回收內存空間。
當
finalize()
方法被調用時,JVM 會釋放該線程上的所有同步鎖。
Class GCScope { GCScope t; static int i = 1; public static void main(String args[]) { GCScope t1 = new GCScope(); GCScope t2 = new GCScope(); GCScope t3 = new GCScope(); // No Object Is Eligible for GC t1.t = t2; // No Object Is Eligible for GC t2.t = t3; // No Object Is Eligible for GC t3.t = t1; // No Object Is Eligible for GC t1 = null; // No Object Is Eligible for GC (t3.t still has a reference to t1) t2 = null; // No Object Is Eligible for GC (t3.t.t still has a reference to t2) t3 = null; // All the 3 Object Is Eligible for GC (None of them have a reference. // only the variable t of the objects are referring each other in a // rounded fashion forming the Island of objects with out any external // reference) } protected void finalize() { System.out.println("Garbage collected from object" + i); i++; } class GCScope { GCScope t; static int i = 1; public static void main(String args[]) { GCScope t1 = new GCScope(); GCScope t2 = new GCScope(); GCScope t3 = new GCScope(); // 沒有對象符合GC t1.t = t2; // 沒有對象符合GC t2.t = t3; // 沒有對象符合GC t3.t = t1; // 沒有對象符合GC t1 = null; // 沒有對象符合GC (t3.t 仍然有一個到 t1 的引用) t2 = null; // 沒有對象符合GC (t3.t.t 仍然有一個到 t2 的引用) t3 = null; // 所有三個對象都符合GC (它們中沒有一個擁有引用。 // 只有各對象的變量 t 還指向了彼此, // 形成了一個由對象組成的環形的島,而沒有任何外部的引用。) } protected void finalize() { System.out.println("Garbage collected from object" + i); i++; }
在判斷哪些內存需要回收和什么時候回收用到GC 算法,本文主要對GC 算法進行講解。
常見的JVM垃圾判定算法包括:引用計數算法、可達性分析算法。
引用計數算法是通過判斷對象的引用數量來決定對象是否可以被回收。
給對象中添加一個引用計數器,每當有一個地方引用它時,計數器值就加1;當引用失效時,計數器值就減1;任何時刻計數器為0的對象就是不可能再被使用的。
優點:簡單,高效,現在的objective-c用的就是這種算法。
缺點:很難處理循環引用,相互引用的兩個對象則無法釋放。因此目前主流的Java虛擬機都摒棄掉了這種算法。
舉個簡單的例子,對象objA和objB都有字段instance,賦值令objA.instance=objB及objB.instance=objA,除此之外,這兩個對象沒有任何引用,實際上這兩個對象已經不可能再被訪問,但是因為互相引用,導致它們的引用計數都不為0,因此引用計數算法無法通知GC收集器回收它們。
public class ReferenceCountingGC { public 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; System.gc();//GC } }
運行結果
[GC (System.gc()) [PSYoungGen: 3329K->744K(38400K)] 3329K->752K(125952K), 0.0341414 secs] [Times: user=0.00 sys=0.00, real=0.06 secs] [Full GC (System.gc()) [PSYoungGen: 744K->0K(38400K)] [ParOldGen: 8K->628K(87552K)] 752K->628K(125952K), [Metaspace: 3450K->3450K(1056768K)], 0.0060728 secs] [Times: user=0.05 sys=0.00, real=0.01 secs] Heap PSYoungGen total 38400K, used 998K [0x00000000d5c00000, 0x00000000d8680000, 0x0000000100000000) eden space 33280K, 3% used [0x00000000d5c00000,0x00000000d5cf9b20,0x00000000d7c80000) from space 5120K, 0% used [0x00000000d7c80000,0x00000000d7c80000,0x00000000d8180000) to space 5120K, 0% used [0x00000000d8180000,0x00000000d8180000,0x00000000d8680000) ParOldGen total 87552K, used 628K [0x0000000081400000, 0x0000000086980000, 0x00000000d5c00000) object space 87552K, 0% used [0x0000000081400000,0x000000008149d2c8,0x0000000086980000) Metaspace used 3469K, capacity 4496K, committed 4864K, reserved 1056768K class space used 381K, capacity 388K, committed 512K, reserved 1048576K Process finished with exit code 0
從運行結果看,GC日志中包含“3329K->744K”,意味著虛擬機并沒有因為這兩個對象互相引用就不回收它們,說明虛擬機不是通過引用技術算法來判斷對象是否存活的。
可達性分析算法是通過判斷對象的引用鏈是否可達來決定對象是否可以被回收。
從GC Roots(每種具體實現對GC Roots有不同的定義)作為起點,向下搜索它們引用的對象,可以生成一棵引用樹,樹的節點視為可達對象,反之視為不可達。
在Java語言中,可以作為GC Roots的對象包括下面幾種:
虛擬機棧(棧幀中的本地變量表)中的引用對象。
方法區中的類靜態屬性引用的對象。
方法區中的常量引用的對象。
本地方法棧中JNI(Native方法)的引用對象
真正標記以為對象為可回收狀態至少要標記兩次。
強引用就是指在程序代碼之中普遍存在的,類似”Object obj = new Object()”這類的引用,只要強引用還存在,垃圾收集器永遠不會回收掉被引用的對象。
Object obj = new Object();
軟引用是用來描述一些還有用但并非必需的對象,對于軟引用關聯著的對象,在系統將要發生內存溢出異常之前,將會把這些對象列進回收范圍進行第二次回收。如果這次回收還沒有足夠的內存,才會拋出內存溢出異常。在JDK1.2之后,提供了SoftReference類來實現軟引用。
Object obj = new Object(); SoftReference<Object> sf = new SoftReference<Object>(obj);
弱引用也是用來描述非必需對象的,但是它的強度比軟引用更弱一些,被弱引用關聯的對象,只能生存到下一次垃圾收集發生之前。當垃圾收集器工作時,無論當前內存是否足夠,都會回收掉只被弱引用關聯的對象。在JDK1.2之后,提供了WeakReference類來實現弱引用。
Object obj = new Object(); WeakReference<Object> wf = new WeakReference<Object>(obj);
虛引用也成為幽靈引用或者幻影引用,它是最弱的一中引用關系。一個對象是否有虛引用的存在,完全不會對其生存時間構成影響,也無法通過虛引用來取得一個對象實例。為一個對象設置虛引用關聯的唯一目的就是能在這個對象被收集器回收時收到一個系統通知。在JDK1.2之后,提供給了PhantomReference類來實現虛引用。
Object obj = new Object(); PhantomReference<Object> pf = new PhantomReference<Object>(obj);
常見的垃圾回收算法包括:標記-清除算法,復制算法,標記-整理算法,分代收集算法。
在介紹JVM垃圾回收算法前,先介紹一個概念。
Stop-the-World
Stop-the-world意味著 JVM由于要執行GC而停止了應用程序的執行,并且這種情形會在任何一種GC算法中發生。當Stop-the-world發生時,除了GC所需的線程以外,所有線程都處于等待狀態直到GC任務完成。事實上,GC優化很多時候就是指減少Stop-the-world發生的時間,從而使系統具有高吞吐 、低停頓的特點。
之所以說標記/清除算法是幾種GC算法中最基礎的算法,是因為后續的收集算法都是基于這種思路并對其不足進行改進而得到的。標記/清除算法的基本思想就跟它的名字一樣,分為“標記”和“清除”兩個階段:首先標記出所有需要回收的對象,在標記完成后統一回收所有被標記的對象。
標記階段:標記的過程其實就是前面介紹的可達性分析算法的過程,遍歷所有的GC Roots對象,對從GC Roots對象可達的對象都打上一個標識,一般是在對象的header中,將其記錄為可達對象;
清除階段:清除的過程是對堆內存進行遍歷,如果發現某個對象沒有被標記為可達對象(通過讀取對象header信息),則將其回收。
不足:
標記和清除過程效率都不高
會產生大量碎片,內存碎片過多可能導致無法給大對象分配內存。
將內存劃分為大小相等的兩塊,每次只使用其中一塊,當這一塊內存用完了就將還存活的對象復制到另一塊上面,然后再把使用過的內存空間進行一次清理。
現在的商業虛擬機都采用這種收集算法來回收新生代,但是并不是將內存劃分為大小相等的兩塊,而是分為一塊較大的 Eden 空間和兩塊較小的 Survior 空間,每次使用 Eden 空間和其中一塊 Survivor。在回收時,將 Eden 和 Survivor 中還存活著的對象一次性復制到另一塊 Survivor 空間上,最后清理 Eden 和 使用過的那一塊 Survivor。HotSpot 虛擬機的 Eden 和 Survivor 的大小比例默認為 8:1,保證了內存的利用率達到 90 %。如果每次回收有多于 10% 的對象存活,那么一塊 Survivor 空間就不夠用了,此時需要依賴于老年代進行分配擔保,也就是借用老年代的空間。
不足:
將內存縮小為原來的一半,浪費了一半的內存空間,代價太高;如果不想浪費一半的空間,就需要有額外的空間進行分配擔保,以應對被使用的內存中所有對象都100%存活的極端情況,所以在老年代一般不能直接選用這種算法。
復制收集算法在對象存活率較高時就要進行較多的復制操作,效率將會變低。
標記—整理算法和標記—清除算法一樣,但是標記—整理算法不是把存活對象復制到另一塊內存,而是把存活對象往內存的一端移動,然后直接回收邊界以外的內存,因此其不會產生內存碎片。標記—整理算法提高了內存的利用率,并且它適合在收集對象存活時間較長的老年代。
不足:
效率不高,不僅要標記存活對象,還要整理所有存活對象的引用地址,在效率上不如復制算法。
分代回收算法實際上是把復制算法和標記整理法的結合,并不是真正一個新的算法,一般分為:老年代(Old Generation)和新生代(Young Generation),老年代就是很少垃圾需要進行回收的,新生代就是有很多的內存空間需要回收,所以不同代就采用不同的回收算法,以此來達到高效的回收算法。
新生代:由于新生代產生很多臨時對象,大量對象需要進行回收,所以采用復制算法是最高效的。
老年代:回收的對象很少,都是經過幾次標記后都不是可回收的狀態轉移到老年代的,所以僅有少量對象需要回收,故采用標記清除或者標記整理算法。
到此,關于“JVM垃圾回收基本原理是什么”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。