国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

理解并解決IE的內存泄漏方式

2019-11-18 11:35:27
字體:
來源:轉載
供稿:網友
   本文將講書述losures引起的IE內存泄漏,在本文中Closures翻譯成閉包或閉包函數。最近在網上看到一個對Closures的解釋,它是這么說的:

<Html>
<HEAD>
<script language="javascript">
function initpage()
{
  window.setTimeout("window.location.reload()", 500, "Javascript");
}
</script>
</HEAD>
<body onload="initpage()" >
<div class='menu' id='menu'></div>
<script language='javascript'>
hookup(document.getElementById('menu'));
function hookup(element)
{
  element.attachEvent( "onmouSEOver", mouse);
  function mouse ()
  {}
}
</script>
</body>
</HTML>
In this code, the handler (the mouse function) is nested inside the attacher (the hookup function). This arrangement means that the handler is closed over the scope of the caller (this arrangement is named a "closure").

閉包函數(Closures)

   由于閉包函數會使程序員在不知不覺中創建出循環引用,所以它對資源泄漏經常有著不可推卸的責任。而在閉包函數自己被釋放前,我們很難判定父函數的參數以及它的局部變量是否能被釋放。實際上閉包函數的使用已經很普通,以致人們頻繁的碰到這類問題時我們卻束手無策。在具體了解了閉包背后的問題和一些非凡的閉包泄漏示例后,我們將結合循環引用的圖示找到閉包的所在,并找出這些不受歡迎的引用來至何處。

理解并解決IE的內存泄漏方式
Figure 1. 閉包函數引起的循環引用
   普通的循環引用,是兩個不可探知的對象相互引用造成的,但是閉包卻不同。代替直接造成引用,閉包函數則取而代之從其父函數作用域中引入信息。通常,函數的局部變量和參數只能在該被調函數自身的生命周期里使用。當存在閉包函數后,這些變量和參數的引用會和閉包函數一起存在,但由于閉包函數可以超越其父函數的生命周期而存在,所以父函數中的局部變量和參數也仍然能被訪問。在下面的示例中,參數1將在函數調用終止時正常被釋放。當我們加入了一個閉包函數后,一個額外的引用產生,并且這個引用在閉包函數釋放前都不會被釋放。假如你碰巧將閉包函數放入了事件之中,那么你不得不手動從那個事件中將其移出。假如你把閉包函數作為了一個eXPando屬性,那么你也需要通過置null將其清除。

   同時閉包會在每次調用中創建,也就是說當你調用包含閉包的函數兩次,你將得到兩個獨立的閉包,而且每個閉包都分別擁有對參數的引用。由于這些顯而易見的因素,閉包確實非常用以帶來泄漏。下面的示例將展示使用閉包的主要泄漏因素:

<html>
<head>
<script language="JScript">

function AttachEvents(element)
{
  // This strUCture causes element to ref ClickEventHandler
  element.attachEvent("onclick", ClickEventHandler);

  function ClickEventHandler()
  {
   // This closure refs element
  }
}

function SetupLeak()
{
  // The leak happens all at once
  AttachEvents(document.getElementById("LeakedDiv"));
}

function BreakLeak()
{}
</script>
</head>
<body onload="SetupLeak()" onunload="BreakLeak()">
<div id="LeakedDiv"></div>
</body>
</html>

   假如你對怎么避免這類泄漏感到迷惑,我將告訴你處理它并不像處理普通循環引用那么簡單。"閉包"被看作函數作用域中的一個臨時對象。一旦函數執行退出,你將失去對閉包本身的引用,那么你將怎樣去調用detachEvent方法來清除引用呢?在Scott Isaacs的MSN Spaces上有一種解決這個問題的有趣方法。這個方法使用一個額外的引用(原文叫second closure,可是這個示例里致始致終只有一個closure)協助window對象執行onUnload事件,由于這個額外的引用和閉包的引用存在于同一個對象域中,于是我們可以借助它來釋放事件引用,從而完成引用移除。為了簡單起見我們將閉包的引用暫存在一個expando屬性中,下面的示例將向你演示釋放事件引用和清除expando屬性。

<html>
<head>
<script language="JScript">

function AttachEvents(element)
{
  // In order to remove this we need to put
  // it somewhere. Creates another ref
  element.expandoClick = ClickEventHandler;

  // This structure causes element to ref ClickEventHandler
  element.attachEvent("onclick", element.expandoClick);

  function ClickEventHandler()
  {
   // This closure refs element
  }
}

function SetupLeak()
{
  // The leak happens all at once
  AttachEvents(document.getElementById("LeakedDiv"));
}

function BreakLeak()
{
  document.getElementById("LeakedDiv").detachEvent("onclick",
  document.getElementById("LeakedDiv").expandoClick);
  document.getElementById("LeakedDiv").expandoClick = null;
}
</script>
</head>
<body onload="SetupLeak()" onunload="BreakLeak()">
<div id="LeakedDiv"></div>
</body>
</html>

   在這篇文章中,實際上建議我們除非迫不得已盡量不要創建使用閉包。文章中的示例,給我們演示了非閉包的事件引用方式,即把閉包函數放到頁面的全局作用域中。當閉包函數成為普通函數后,它將不再繼續其父函數的參數和局部變量,所以我們也就不用擔心基于閉包的循環引用了。在非必要的時候不使用閉包這樣的編程方式可以盡量使我們的代碼避免這樣的問題。

   最后,腳本引擎開發組的Eric Lippert,給我們帶來了一篇關于閉包使用通俗易懂的好文章。他的最終建議也是希望在真正必要的時候才使用閉包函數。雖然他的文章沒有提及閉包會使用的真正場景,但是這兒已有的大量示例非常有助于大家起步。

   不得不說Eric Lippert同志疾呼的:Don't use closures unless you really need closure semantics. In most cases, non-nested functions are the right way to go. 是非常消極的應付之辭。今天關于IE內存泄漏的文章已有很多,而且很大部分就是微軟的自己人在解釋,甚至象Eric Lippert這樣引擎開發組的成員。但是他們的文章始終沒有正面承認其實這就是IE的bug,而且是非常嚴重的bug,這事情其實完全不關腳本引擎對象和DOM對象的事。就是微軟對產品不負責任的表現,不說IE4,1997那個春天那是太遙遠了點,但是IE6也是2001年隨xp發布的。使用COM可以給他們的開發帶來很多便利,當然也利用很多現成的東西,可是居然在帶來這樣的嚴重問題后,他們卻把大部分責任歸咎于不合理和不正確的使用Closures技術!對于循環引用產生Memory Leak我根本就是不好意思提了,那樣的問題是應該發生的嗎?那就讓我們拭目以待看IE7怎么解決這堆shit問題吧,當然我希望不要再看到類似:Do not use closures unless they are necessary. 這樣的扯淡建議!

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 隆安县| 沁阳市| 南岸区| 耿马| 宝清县| 读书| 云安县| 新竹市| 炎陵县| 金堂县| 乌鲁木齐市| 东乡县| 合江县| 定南县| 乌兰察布市| 阳西县| 修武县| 贺兰县| 克拉玛依市| 苍溪县| 平阴县| 海南省| 伊春市| 阿拉善左旗| 宁陕县| 定结县| 高青县| 咸宁市| 通江县| 兰坪| 邯郸县| 云安县| 巴彦淖尔市| 黑山县| 巴塘县| 阳高县| 西峡县| 武城县| 独山县| 民勤县| 嵩明县|