欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

一文搞懂如何避免JavaScript內(nèi)存泄漏

 更新時(shí)間:2022年05月26日 16:55:49   作者:CUGGZ  
SPA的興起,促使我們更加關(guān)注與內(nèi)存相關(guān)的JavaScript編碼實(shí)踐。如果應(yīng)用使用的內(nèi)存越來(lái)越多,就會(huì)嚴(yán)重影響性能,甚至導(dǎo)致瀏覽器的崩潰。下面就來(lái)看看JavaScript中常見(jiàn)的內(nèi)存泄漏以及如何避免內(nèi)存泄漏

大家好,我是CUGGZ。SPA(單頁(yè)應(yīng)用程序)的興起,促使我們更加關(guān)注與內(nèi)存相關(guān)的 JavaScript 編碼實(shí)踐。如果應(yīng)用使用的內(nèi)存越來(lái)越多,就會(huì)嚴(yán)重影響性能,甚至導(dǎo)致瀏覽器的崩潰。下面就來(lái)看看JavaScript中常見(jiàn)的內(nèi)存泄漏以及如何避免內(nèi)存泄漏。

一、什么是內(nèi)存泄漏

JavaScript 就是所謂的垃圾回收語(yǔ)言之一,垃圾回收語(yǔ)言通過(guò)定期檢查哪些先前分配的內(nèi)存仍然可以從應(yīng)用程序的其他部分“訪問(wèn)”來(lái)幫助開(kāi)發(fā)人員管理內(nèi)存。垃圾回收語(yǔ)言中泄漏的主要原因是不需要的引用。如果你的 JavaScript 應(yīng)用程序經(jīng)常發(fā)生崩潰、高延遲和性能差,那么一個(gè)潛在的原因可能是內(nèi)存泄漏。

在 JavaScript 中,內(nèi)存是有生命周期的:

  • 分配內(nèi)存: 內(nèi)存由操作系統(tǒng)分配,允許程序使用它。在 JavaScript 中,分配內(nèi)存是自動(dòng)完成的。
  • 使用內(nèi)存: 這是程序?qū)嶋H使用先前分配的內(nèi)存的空間。當(dāng)在代碼中使用分配的變量時(shí),會(huì)發(fā)生讀取和寫入操作。
  • 釋放內(nèi)存: 釋放不需要的內(nèi)存,這樣內(nèi)存就會(huì)空閑并可以再次利用。在 JavaScript 中,釋放內(nèi)存是自動(dòng)完成的。

在JavaScript中,對(duì)象會(huì)保存在堆內(nèi)存中,可以根據(jù)引用鏈從根訪問(wèn)它們。垃圾收集器是 JavaScript 引擎中的一個(gè)后臺(tái)進(jìn)程,用于識(shí)別無(wú)法訪問(wèn)的對(duì)象、刪除它們并回收內(nèi)存。

下面是垃圾收集器根到對(duì)象的引用鏈?zhǔn)纠?/p>

當(dāng)內(nèi)存中應(yīng)該在垃圾回收周期中清理的對(duì)象,通過(guò)另一個(gè)對(duì)象的無(wú)意引用從根保持可訪問(wèn)時(shí),就會(huì)發(fā)生內(nèi)存泄漏。將冗余對(duì)象保留在內(nèi)存中會(huì)導(dǎo)致應(yīng)用程序內(nèi)部使用過(guò)多的內(nèi)存,并可能導(dǎo)致性能下降。

那該如何判斷代碼正在泄漏內(nèi)存呢?通常,內(nèi)存泄漏是很難被發(fā)現(xiàn)的,并且瀏覽器在運(yùn)行它時(shí)不會(huì)拋出任何錯(cuò)誤。如果注意到頁(yè)面的性能越來(lái)越差,瀏覽器的內(nèi)置工具可以幫助我們確定是否存在內(nèi)存泄漏以及導(dǎo)致內(nèi)存泄漏的對(duì)象。

內(nèi)存使用檢查最快的方法就是查看瀏覽器的任務(wù)管理器。 它們提供了當(dāng)前在瀏覽器中運(yùn)行的所有選項(xiàng)卡和進(jìn)程的概覽。在任務(wù)管理器中查看每個(gè)選項(xiàng)卡的 JavaScript 內(nèi)存占用情況。如果網(wǎng)站什么都不做,但是 JavaScript 內(nèi)存使用量卻在逐漸增加,那么很有可能發(fā)生了內(nèi)存泄漏。

二、常見(jiàn)的內(nèi)存泄漏

我們可以通過(guò)了解在 JavaScript 中如何創(chuàng)建不需要的引用來(lái)防止內(nèi)存泄漏。以下情況就會(huì)導(dǎo)致不需要的引用。

1、意外的全局變量

全局變量始終可以從全局對(duì)象(在瀏覽器中,全局對(duì)象是window)中獲得,并且永遠(yuǎn)不會(huì)被垃圾回收。在非嚴(yán)格模式下,以下行為會(huì)導(dǎo)致變量從局部范圍泄露到全局范圍:

(1)為未聲明的變量賦值

這里我們給函數(shù)中一個(gè)未聲明的變量bar賦值,這時(shí)就會(huì)使bar成為一個(gè)全局變量:

function foo(arg) {
    bar = "hello world";
}

這就等價(jià)于:

function foo(arg) {
    window.bar = "hello world";
}

這樣就會(huì)創(chuàng)建一個(gè)多余的全局變量,當(dāng)執(zhí)行完foo函數(shù)之后,變量bar仍然會(huì)存在于全局對(duì)象中:

foo()
window.bar   // hello world

(2)使用指向全局對(duì)象的 this

使用以下方式也會(huì)創(chuàng)建一個(gè)以外的全局變量:

function foo() {
    this.bar = "hello world";
}

foo();

這里foo是在全局對(duì)象中調(diào)用的,所以其this是指向全局對(duì)象的(這里是window):

window.bar   // hello world

我們可以通過(guò)使用嚴(yán)格模式“use strict”來(lái)避免這一切。在JavaScript文件的開(kāi)頭,它將開(kāi)啟更嚴(yán)格的JavaScript解析模式,從而防止意外的創(chuàng)建全局變量。

需要特別注意那些用于臨時(shí)存儲(chǔ)和處理大量信息的全局變量。如果必須使用全局變量存儲(chǔ)數(shù)據(jù),就使用全局變量存儲(chǔ)數(shù)據(jù),但在不再使用時(shí),就手動(dòng)將其設(shè)置為 null,或者在處理完后重新分配。否則的話,請(qǐng)盡可能的使用局部變量。

2、 計(jì)時(shí)器

使用 setTimeout 或 setInterval 引用回調(diào)中的某個(gè)對(duì)象是防止對(duì)象被垃圾收集的最常見(jiàn)方法。如果我們?cè)诖a中設(shè)置了循環(huán)計(jì)時(shí)器,只要回調(diào)是可調(diào)用的,計(jì)時(shí)器回調(diào)中對(duì)對(duì)象的引用就會(huì)保持活動(dòng)狀態(tài)。

在下面的示例中,只有在清除計(jì)時(shí)器后,才能對(duì)數(shù)據(jù)對(duì)象進(jìn)行垃圾收集。由于我們沒(méi)有對(duì)setInterval的引用,所以它永遠(yuǎn)無(wú)法被清除和刪除數(shù)據(jù)。hugeString會(huì)一直保存在內(nèi)存中,直到應(yīng)用程序停止,盡管從未使用過(guò)。

function setCallback() {
  const data = {
    counter: 0,
    hugeString: new Array(100000).join('x')
  };

  return function cb() {
    data.counter++;   // data對(duì)象是回調(diào)范圍的一部分
    console.log(data.counter);
  }
}

setInterval(setCallback(), 1000);

當(dāng)執(zhí)行這段代碼時(shí),就會(huì)每秒輸出一個(gè)數(shù)字:

那我們?nèi)绾稳プ柚顾?尤其是在回調(diào)的壽命未定義或不確定的情況下:

  • 修改計(jì)時(shí)器回調(diào)中引用的對(duì)象;
  • 必要時(shí)使用從計(jì)時(shí)器返回的句柄(定時(shí)器的標(biāo)識(shí)符)取消它。
function setCallback() {
  // 將數(shù)據(jù)對(duì)象解包
  let counter = 0;
  const hugeString = new Array(100000).join('x'); // 在setCallback返回時(shí)被刪除
  
  return function cb() {
    counter++; // 只有計(jì)數(shù)器counter是回調(diào)范圍的一部分
    console.log(counter);
  }
}

const timerId = setInterval(setCallback(), 1000); // 保存定時(shí)器的ID

// 合適的時(shí)機(jī)清除定時(shí)器
clearInterval(timerId);

3、 閉包

我們知道,函數(shù)范圍內(nèi)的變量在函數(shù)退出調(diào)用堆棧后,如果函數(shù)外部沒(méi)有任何指向它們的引用,則會(huì)被清除。盡管函數(shù)已經(jīng)完成執(zhí)行,其執(zhí)行上下文和變量環(huán)境早已消失,但閉包將保持變量的引用和活動(dòng)狀態(tài)。

function outer() {
  const potentiallyHugeArray = [];

  return function inner() {
    potentiallyHugeArray.push('Hello');  
    console.log('Hello');
  };
};

const sayHello = outer();

function repeat(fn, num) {
  for (let i = 0; i < num; i++){
    fn();
  }
}
repeat(sayHello, 10);

顯而易見(jiàn),這里就形成了一個(gè)閉包。其輸出結(jié)果如下:

這里,potentiallyHugeArray 永遠(yuǎn)不會(huì)從任何函數(shù)返回,也無(wú)法訪問(wèn),但它的大小可能會(huì)無(wú)限增長(zhǎng),這取決于調(diào)用函數(shù) inner() 的次數(shù)。

那該如何防止這個(gè)問(wèn)題呢?閉包是不可避免的,也是JavaScript不可或缺的一部分,因此重要的是:

  • 了解何時(shí)創(chuàng)建閉包以及閉包保留了哪些對(duì)象。
  • 了解閉包的預(yù)期壽命和用法(尤其是用作回調(diào)時(shí))。

4、 事件監(jiān)聽(tīng)器

活動(dòng)事件偵聽(tīng)器將防止在其范圍內(nèi)捕獲的所有變量被垃圾收集。添加后,事件偵聽(tīng)器將一直有效,直到:

  • 使用 removeEventListener() 顯式刪除。
  • 關(guān)聯(lián)的 DOM 元素被移除。

對(duì)于某些類型的事件,它會(huì)一直保留到用戶離開(kāi)頁(yè)面,就像應(yīng)該多次單擊的按鈕一樣。但是,有時(shí)我們希望事件偵聽(tīng)器執(zhí)行一定次數(shù)。

const hugeString = new Array(100000).join('x');
document.addEventListener('keyup', function() { // 匿名內(nèi)聯(lián)函數(shù),無(wú)法刪除它
  doSomething(hugeString); // hugeString 將永遠(yuǎn)保留在回調(diào)的范圍內(nèi)
});

在上面的示例中,匿名內(nèi)聯(lián)函數(shù)用作事件偵聽(tīng)器,這意味著不能使用 removeEventListener() 刪除它。同樣,document 不能被刪除,因此只能使用 listener 函數(shù)以及它在其范圍內(nèi)保留的內(nèi)容,即使只需要啟動(dòng)一次。

那該如何防止這個(gè)問(wèn)題呢?一旦不再需要,我們應(yīng)該通過(guò)創(chuàng)建指向事件偵聽(tīng)器的引用并將其傳遞給 removeEventListener() 來(lái)注銷事件偵聽(tīng)器。

function listener() {
  doSomething(hugeString);
}
document.addEventListener('keyup', listener); 
document.removeEventListener('keyup', listener);

如果事件偵聽(tīng)器只能執(zhí)行一次,addEventListener() 可以接受第三個(gè)參數(shù),這是一個(gè)提供附加選項(xiàng)的對(duì)象。假定將 {once:true} 作為第三個(gè)參數(shù)傳遞給 addEventListener() ,則偵聽(tīng)器函數(shù)將在處理一次事件后自動(dòng)刪除。

document.addEventListener('keyup', function listener() {
  doSomething(hugeString);
}, {once: true});

5、緩存

如果我們不斷地將內(nèi)存添加到緩存中,而不刪除未使用的對(duì)象,并且沒(méi)有一些限制大小的邏輯,那么緩存可以無(wú)限增長(zhǎng)。

let user_1 = { name: "Peter", id: 12345 };
let user_2 = { name: "Mark", id: 54321 };
const mapCache = new Map();
function cache(obj){
  if (!mapCache.has(obj)){
    const value = `${obj.name} has an id of ${obj.id}`;
    mapCache.set(obj, value);
    return [value, 'computed'];
  }
  return [mapCache.get(obj), 'cached'];
}
cache(user_1); // ['Peter has an id of 12345', 'computed']
cache(user_1); // ['Peter has an id of 12345', 'cached']
cache(user_2); // ['Mark has an id of 54321', 'computed']
console.log(mapCache); // {{…} => 'Peter has an id of 12345', {…} => 'Mark has an id of 54321'}
user_1 = null;
console.log(mapCache); // {{…} => 'Peter has an id of 12345', {…} => 'Mark has an id of 54321'}

在上面的示例中,緩存仍然保留 user_1 對(duì)象。因此,我們需要將那些永遠(yuǎn)不會(huì)被重用的變量從緩存中清除。

可以使用 WeakMap 來(lái)解決此問(wèn)題。它是一種具有弱鍵引用的數(shù)據(jù)結(jié)構(gòu),僅接受對(duì)象作為鍵。如果我們使用一個(gè)對(duì)象作為鍵,并且它是對(duì)該對(duì)象的唯一引用——相關(guān)變量將從緩存中刪除并被垃圾收集。在以下示例中,將 user_1 對(duì)象清空后,相關(guān)變量會(huì)在下一次垃圾回收后自動(dòng)從 WeakMap 中刪除。

let user_1 = { name: "Peter", id: 12345 };
let user_2 = { name: "Mark", id: 54321 };
const weakMapCache = new WeakMap();
function cache(obj){
  // ...
  return [weakMapCache.get(obj), 'cached'];
}
cache(user_1); // ['Peter has an id of 12345', 'computed']
cache(user_2); // ['Mark has an id of 54321', 'computed']
console.log(weakMapCache); // {(…) => "Peter has an id of 12345", (…) => "Mark has an id of 54321"}
user_1 = null;
console.log(weakMapCache); // {(…) => "Mark has an id of 54321"}

6、分離的DOM元素

如果DOM節(jié)點(diǎn)具有來(lái)自 JavaScript 的直接引用,它將防止對(duì)其進(jìn)行垃圾收集,即使在從DOM樹(shù)中刪除該節(jié)點(diǎn)之后也是如此。

在下面的示例中,創(chuàng)建了一個(gè)div元素并將其附加到 document.body 中。removeChild() 就無(wú)法按預(yù)期工作,堆快照將顯示分離的HTMLDivElement,因?yàn)槿杂幸粋€(gè)變量指向div。

function createElement() {
  const div = document.createElement('div');
  div.id = 'detached';
  return div;
}
// 即使在調(diào)用deleteElement() 之后,它仍將繼續(xù)引用DOM元素
const detachedDiv = createElement();
document.body.appendChild(detachedDiv);
function deleteElement() {
  document.body.removeChild(document.getElementById('detached'));
}
deleteElement();

要解決此問(wèn)題,可以將DOM引用移動(dòng)到本地范圍。在下面的示例中,在函數(shù)appendElement() 完成后,將刪除指向DOM元素的變量。

function createElement() {...}
// DOM引用在函數(shù)范圍內(nèi)
function appendElement() {
  const detachedDiv = createElement();
  document.body.appendChild(detachedDiv);
}
appendElement();
function deleteElement() {
  document.body.removeChild(document.getElementById('detached'));
}
deleteElement();

三、識(shí)別內(nèi)存泄漏

調(diào)試內(nèi)存問(wèn)題是一項(xiàng)復(fù)雜的工作,我們可以使用 Chrome DevTools 來(lái)識(shí)別內(nèi)存圖和一些內(nèi)存泄漏,我們需要關(guān)注以下兩個(gè)方面:

  • 使用性能分析器可視化內(nèi)存消耗。
  • 識(shí)別分離的 DOM 節(jié)點(diǎn)。

1、使用性能分析器可視化內(nèi)存消耗

以下面的代碼為例,有兩個(gè)按鈕:打印和清除。點(diǎn)擊“打印”按鈕,通過(guò)創(chuàng)建 paragraph 節(jié)點(diǎn)并將大字符串設(shè)置到全局,將1到10000的數(shù)字追加到DOM中。

“清除”按鈕會(huì)清除全局變量并覆蓋 body 的正文,但不會(huì)刪除單擊“打印”時(shí)創(chuàng)建的節(jié)點(diǎn):

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Memory leaks</title>
  </head>
  <body>
    <button id="print">打印</button>
    <button id="clear">清除</button>
  </body>
</html>
<script>
  var longArray = [];
  
  function print() {
    for (var i = 0; i < 10000; i++) {
      let paragraph = document.createElement("p");
      paragraph.innerHTML = i;
      document.body.appendChild(paragraph);
    }
    longArray.push(new Array(1000000).join("y"));
  }
  
  document.getElementById("print").addEventListener("click", print);
  document.getElementById("clear").addEventListener("click", () => {
    window.longArray = null;
    document.body.innerHTML = "Cleared";
  });
</script>

當(dāng)每次點(diǎn)擊打印按鈕時(shí),JavaScript Heap都會(huì)出現(xiàn)藍(lán)色的峰值,并逐漸增加,這是因?yàn)镴avaScript正在創(chuàng)建DOM節(jié)點(diǎn)并字符串添加到全局?jǐn)?shù)組。當(dāng)點(diǎn)擊清除按鈕時(shí),JavaScript Heap就變得正常了。除此之外,可以看到節(jié)點(diǎn)的數(shù)量(綠色的線)一直在增加,因?yàn)槲覀儾](méi)有刪除這些節(jié)點(diǎn)。

在實(shí)際的場(chǎng)景中,如果觀察到內(nèi)存持續(xù)出現(xiàn)峰值,并且內(nèi)存消耗一直沒(méi)有減少,那可能存在內(nèi)存泄露。

2、 識(shí)別分離的 DOM 節(jié)點(diǎn)

當(dāng)一個(gè)節(jié)點(diǎn)從 DOM 樹(shù)中移除時(shí),它被稱為分離,但一些 JavaScript 代碼仍然在引用它。讓我們使用下面的代碼片段檢查分離的 DOM 節(jié)點(diǎn)。通過(guò)單擊按鈕,可以將列表元素添加到其父級(jí)中并將父級(jí)分配給全局變量。簡(jiǎn)單來(lái)說(shuō),全局變量保存著 DOM 引用:

var detachedElement;
function createList(){
  let ul = document.createElement("ul");
  for(let i = 0; i < 5; i++){
    ul.appendChild(document.createElement("li"));
  }
  detachedElement = ul;
}
document.getElementById("createList").addEventListener("click", createList);

我們可以使用 heap snapshot 來(lái)檢查分離的DOM節(jié)點(diǎn),可以在Chrome DevTools 的Memory面板中打開(kāi)Heap snapshots選項(xiàng):

點(diǎn)擊頁(yè)面的按鈕后,點(diǎn)擊下面藍(lán)色的Take snapshot按鈕,我們可以在中間的搜索欄目輸入Detached來(lái)過(guò)濾結(jié)果以找到分離的DOM節(jié)點(diǎn),如下所示:

當(dāng)然也可以嘗試使用此方法來(lái)識(shí)別其他內(nèi)存泄漏。

到此這篇關(guān)于一文搞懂如何避免JavaScript內(nèi)存泄漏的文章就介紹到這了,更多相關(guān)JavaScript內(nèi)存泄漏內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 仿新浪微博登陸郵箱提示效果的js代碼

    仿新浪微博登陸郵箱提示效果的js代碼

    本文為大家介紹下使用js仿新浪微博登陸郵箱提示效果,具體實(shí)現(xiàn)代碼如下,感興趣的朋友可以參考下,希望對(duì)大家有所幫組
    2013-08-08
  • JS常見(jiàn)問(wèn)題整理(持續(xù)更新)

    JS常見(jiàn)問(wèn)題整理(持續(xù)更新)

    JS常見(jiàn)問(wèn)題在開(kāi)發(fā)過(guò)程中會(huì)經(jīng)常遇到過(guò),本文整理了一些實(shí)際開(kāi)發(fā)中存在的問(wèn)題,曬出來(lái)與大家一起分享,感興趣的朋友可以參考下,希望對(duì)大家有所幫助
    2013-08-08
  • 利用prop-types第三方庫(kù)對(duì)組件的props中的變量進(jìn)行類型檢測(cè)

    利用prop-types第三方庫(kù)對(duì)組件的props中的變量進(jìn)行類型檢測(cè)

    本篇文章主要介紹了利用prop-types第三方庫(kù)對(duì)組件的props中的變量進(jìn)行類型檢測(cè)的相關(guān)知識(shí),具有很好的參考價(jià)值。下面跟著小編一起來(lái)看下吧
    2017-05-05
  • uniapp微信小程序訂閱消息發(fā)送服務(wù)通知超詳細(xì)教程

    uniapp微信小程序訂閱消息發(fā)送服務(wù)通知超詳細(xì)教程

    在使用或開(kāi)發(fā)小程序過(guò)程中,我們會(huì)發(fā)現(xiàn)消息通知是非常重要的一個(gè)環(huán)節(jié),下面這篇文章主要給大家介紹了關(guān)于uniapp微信小程序訂閱消息發(fā)送服務(wù)通知的相關(guān)資料,需要的朋友可以參考下
    2023-06-06
  • 如何檢測(cè)JavaScript的各種類型

    如何檢測(cè)JavaScript的各種類型

    在寫js腳本的時(shí)候我們必須對(duì)一件事保持警惕,就是避免異常的發(fā)生。在本篇文章里面,我想談?wù)勔徊糠诸愋蜋z測(cè),有需要的可以參考學(xué)習(xí)。
    2016-07-07
  • JavaScript如何正確的寫代碼注釋

    JavaScript如何正確的寫代碼注釋

    這篇文章主要給大家介紹了關(guān)于JavaScript如何正確的寫代碼注釋的相關(guān)資料,注釋的作用是提高代碼的可讀性,幫助自己和別人閱讀和理解你所編寫的JavaScript代碼,注釋的內(nèi)容不會(huì)在網(wǎng)頁(yè)中顯示,需要的朋友可以參考下
    2023-10-10
  • javascript面向?qū)ο蟪绦蛟O(shè)計(jì)高級(jí)特性經(jīng)典教程(值得收藏)

    javascript面向?qū)ο蟪绦蛟O(shè)計(jì)高級(jí)特性經(jīng)典教程(值得收藏)

    這篇文章主要介紹了javascript面向?qū)ο蟪绦蛟O(shè)計(jì)高級(jí)特性,結(jié)合實(shí)例形式詳細(xì)講述了javascript對(duì)象的創(chuàng)建,訪問(wèn),刪除,對(duì)象類型,擴(kuò)展等,需要的朋友可以參考下
    2016-05-05
  • uniapp開(kāi)發(fā)微信小程序自定義頂部導(dǎo)航欄功能實(shí)例

    uniapp開(kāi)發(fā)微信小程序自定義頂部導(dǎo)航欄功能實(shí)例

    uni-app是一個(gè)使用Vue.js開(kāi)發(fā)跨平臺(tái)應(yīng)用的前端框架,下面這篇文章主要給大家介紹了關(guān)于uniapp開(kāi)發(fā)微信小程序自定義頂部導(dǎo)航欄功能的相關(guān)資料,文中通過(guò)圖文以及示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-08-08
  • JS?連接MQTT的使用方法

    JS?連接MQTT的使用方法

    這篇文章主要介紹了JS?連接MQTT的使用方法,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-01-01
  • 深入理解requireJS-實(shí)現(xiàn)一個(gè)簡(jiǎn)單的模塊加載器

    深入理解requireJS-實(shí)現(xiàn)一個(gè)簡(jiǎn)單的模塊加載器

    本篇文章主要介紹了深入理解requireJS-實(shí)現(xiàn)一個(gè)簡(jiǎn)單的模塊加載器,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-01-01

最新評(píng)論