在 JScript 中釋放記憶體、批量載入問題及其他發布日期: 1/24/2005 | 更新日期: 1/24/2005
Nancy Michell 編輯
問:我有一些關於 JScript 中記憶體回收的問題。我認為在 Microsoft Internet Explorer 6.0 中有記憶體流失,但在另一方面,它可能是循環參考問題。在My Code中,我假設“new Object()”屬於 JScript,而“document.createElement”屬於 Internet Explorer DOM,因此 JScript 中的記憶體回收行程無法釋放 DOM 元素。這正確嗎?避免這一問題的最佳方法是什麼呢?
當您將代碼載入到 Internet Explorer 6.0 中並單擊“Refresh”時,您可以在“Task Manager”中觀察到記憶體增加:
<html><body> <script type="text/JScript"> for (i=0; i<1000; i++) { // this loop enforces the effect var model = new Object(); var element = document.createElement("<br>"); model.myElement = element; element.myModel = model; model = null; element = null; } </script></body></html>
答:這不是記憶體流失。您正在頁面上建立新文本一千次!這會使頁面變大。如果您建立了許多無法獲得也無法釋放的對象,那才是記憶體流失。在這裡,您將建立許多元素,Internet Explorer 需要儲存它們以正確呈現頁面。Internet Explorer 並不知道您以後不會運行操縱您剛剛建立的所有這些對象的指令碼。
當頁面消失時(當您瀏覽完,離開瀏覽器時)會釋放記憶體。它不會泄漏。當銷毀頁面時,會中斷循環參考。
問:我試圖通過將 XML 傳遞給將由 ADO.NET SQL 提供者調用的預存程序,來將一些 XML 匯入資料庫。當 XML 檔案太大時,它會由於 SqlException 異常(表示發生了嚴重錯誤)而失敗。我追蹤到 sp_xml_preparedocument 時失敗了。
使用具有 43403 個字元的 XML 檔案時,它運行良好,但是如果我再增加一個字元(通過將最後的 Vendor 欄位從“Micros”更改為“Microso”),它就會失敗。傳遞給預存程序的參數是 ntext 類型的。我無法使用批量載入。這是個已知問題嗎?大小限制是來自 ADO.NET、SQL 還是 sp_xml_preparedocument?最後,有解決方案嗎?
答:實際上,可讓您使用批量載入的一個方法是,將資料載入到分段表中,然後在那裡執行插入和更新操作。直到 sp_xml_preparedocument 失敗,這樣的問題在以前就已經發生過了。大多數都是由於下列原因之一:單個錯誤字元(或錯誤編碼中的字元)使分析器失敗;使用了截斷 XML 的 nvarchar;或者使用 text 替代了 ntext(導致了非法字元)。
雖然有一線希望,但沒有一個是問題的實際原因,所以您應該採取的下一步是嘗試最新的 SQL Server Service Pack (http://www.microsoft.com/sql),目的是看看這是否可以糾正該問題。
問:我要設計一個搜尋介面,並且我想轉變單詞“Go”。許多網站都使用各種語言的“Go”來表示提交功能。但是我應該使用單詞還是某種類型的表徵圖呢?我只能使用箭頭表徵圖嗎?
答:類似圖 1 中所示的箭頭符號都是有方向的,因此它們的解釋依賴於它們所放的位置。文本是沒有方向的,因此它與您決定將它放在哪裡無關;意思也不會變化。
圖 1 箭頭表徵圖
然而研究表明,自報告的使用者首選是一個按鈕而不是其他內容,這並不比第一次遇見時理解介面更重要。對於只是偶然使用的工具或 Web 服務,這確實如此。
無論您為提交按鈕選擇什麼標籤,請記住,支援 Enter 鍵作為搜尋查詢提交選項是非常重要的。使用者很少評論 Enter 鍵的功能,除非沒有它,然後您就會聽到評論!此外,出於可用性目的,提交按鈕插圖應該盡量接近搜尋文字框的提交按鈕(最好在它右邊)。
問:我有一個問題,是關於保持 SQL 資料庫的資料樹結構,並讓該樹變得可搜尋並更快。XML 可以表示該結構,並且我可以將 SQL 用於儲存,但是我希望能夠快速地搜尋資料樹。遺憾的是,該樹有很多分支和樹葉,非常類似於檔案系統中的目錄結構,因此我無法使用固定表關係。構建該資料庫結構的最佳方法是什麼呢?
答:SQLXML 好像在淺層次上比在深層次上執行得更好。隨著 XML 嵌套增加,記憶體使用量率和處理時間也相應地增加了。請閱讀下面這篇有關在 SQL 中處理階層的文章:Expanding Hierarchies。
XML 嵌套得越深,它進行分析或構造(從平面資料)所需的開銷就越大。嘗試使用世界上最快的 XML 分析器對範圍在 1,000-10,000 等級深度的 XML 進行分析。嘗試對相同資料運行一個簡單的 XSLT 指令碼。深層次幾乎總是比淺層次需要更多的開銷。
當通過 XPath 檢索 XML 時,SQLXML 使用 SQL Server FOR XML EXPLICIT 模式,這基本上需要有序的外部聯合。根據各個行業研究,在從平面關係資料構造 XML 時,有序的外部聯合方法通常優於除了混合片段(自適應確定其中的資料粒度,否則進行調整以避免不必要的聯合)以外的任何其他方法。SQLXML 不控制也不修改使用者的資料布局,因此自適應儲存策略不是一個選項。
當通過 updategram 修改 XML 時,SQLXML 會切割資料(將它從分層格式變為平面格式)並產生原子 DML 語句,就像您的樣本中那樣。當通過批量載入插入 XML 時,SQLXML 會再次切割資料,但使用的是 SQL 批量載入操作。兩者都非常有效。
對於檢索,最糟糕的情況是,粗略地獲得每個元素類型(而不是每個元素)的一個選擇,並將所有選擇都聯合在一起,然後通過嵌套的主鍵列進行排序。通常,這種方法會導致兩個主要的效能問題。第一,SQL Server 沒有很好地最佳化計算主鍵列(您應該在帶批註的架構中使用許多 sql:datatype/xsd:type 限定符,這樣 SQLXML 就可以從它產生的查詢中排除不必要的計算)。第二,有序的外部聯合範圍嚴重超出(比如說)上百個元素類型。
您引用的樣本不是橫向比較,因為它沒有產生 XML。產生展示層次結構的平面資料很容易。開銷部分會將平面表示轉換為真正的層次表示 (XML)。階層越深,轉變所需的開銷就越大。如果您對 SQLXML 運行效能分析工具,則會看到大部分處理時間都是由 OLEDB 中的資料類型轉換和從平面行集合到 XML 階層的轉換所佔據,而不是花費在執行 SQL 查詢本身上。最後,您也可以嘗試運行沒有 FOR XML EXPLICIT 的聯集查詢,並驗證該 SQL 查詢不是瓶頸。
如果您選擇使用 XML 來保持資料樹結構,則應該考慮使用 SQLXML3.0 來將該文檔切割成 SQL Server 資料庫。一種可能的解決方案是建立一個描述執行個體 XML 文檔的帶批註的 XSD 架構。最大深度的批註允許您描述遞迴樹結構。SQLXML 批量載入功能允許您將該文檔切割為 SQL Server 資料庫。SQLXML 協助檔案中有一些樣本。請參閱最大深度部分,那裡描述了如何處理不同層次等級的 XML 文檔(只要它們是遞迴的,並且您可以指定等級的最大數目)。
問:我注意到,許多為了訪問某些內容或服務而需要登入的網站不直接將登入框放在首頁上。大多數網站都在首頁頂部的某處包含一個登入連結,甚至根本不在首頁上放置連結,而是在使用者瀏覽到需要登入的網站部分時,將使用者引導到登入頁面。
網站應該在首頁上直接顯示使用者可以輸入使用者名稱和密碼的登入部分嗎?還是一個小的登入連結就足夠了?或者,使用第三種選擇更好,即,僅當使用者需要登入時,才提示他們登入?
答:在某些情況下,在所有頁面上提供使用者名稱和密碼欄位可能也是合適的,而不是將使用者名稱和密碼請求欄位只放在首頁上或者只放在專用於登入的單獨頁面上。這確實會佔用一些螢幕空間,但是它可以提醒未註冊的使用者:如果他們登入,則會獲得更多的資訊。將使用者帶到專用的登入螢幕會使人迷惑,特別是當您將他們返回到其來自的頁面時。
問:假設您有一個函數,該函數有時在 try…… catch…… 內部,但其他時候不在。假設當它在 try catch 中時,我打算再次引發相同的錯誤,但當它不在其中時,我不打算這樣做,因為這樣我將得到一個錯誤 —“已經引發了異常,但沒有捕獲到”。
因此,僅當有一個嵌套的 catch 捕獲它時,我才希望重新引發該錯誤。有沒有一種方法可以斷定,在您引發之前是否有 catch 捕獲到引發?JScript 代碼如下:
try{ // Do something that causes an error}catch(e){ if () { throw(e); } else { // do something }}
答:對不起,沒有方法可以檢測調用方是否會捕獲您引發的異常。然而,您的問題暴露了您應用程式中的一個潛在設計缺陷。引發異常的所有點都說“發生了意外情況,但我不知道如何處理它”。如果您可以不用再次引發該異常就離開,則很顯然,您可以處理這種意外事件。如果您可以處理它並繼續,則就不需要再次引發異常。如果您無法處理它,則請順從您的調用方來處理它。您不應該根據調用方可以處理什麼來進行決定,而應該根據您可以處理什麼來進行決定。
如果沒有調用方可以處理該異常,則正確的做法是停止程式。無法處理意外的程式會遭到極大的破壞,並且在它進行破壞之前必須停止它。如果您的調用方無法處理異常,則要麼重新編寫調用方,要麼不引發異常。
此外,不要總是使用異常作為主要情況的控制流程。異常處理被專門設計和實現為管理致命錯誤,因此這就是它應該用於的全部方面。
問:在 ASP.NET(特別是結合了 Visual Basic)中,您如何將表單資料傳遞給網頁?當呈現 ASP.NET 網頁時,表單的操作欄位會自動更改以傳遞給它自己。我需要顯示登入頁面,並且當使用者單擊“Login”時,可將表單資料傳遞到其他網站(所建立的網站使用 Request.Form 來捕獲我的資料)。我知道我可以自己捕獲資料,並將它傳入查詢字串中,但是這不可選。我必須將它傳遞給其他網站。
答:如果您在表單上只使用 HTMLControl,則您將它傳遞到另一個頁面所需要做的就是從 FORM 標記中刪除 runat="server",並將操作屬性設定為您需要傳遞到的 URL。如果您不添加 runat="server",則會將 FORM 元素髮送到不變的用戶端。這不會妨礙您在 Web Form的 Page_Load 事件中設定表單上的 HTMLControl 值。
如果您使用 WebControl,則在表單上需要 runat="server"。然而,您仍然可以傳遞到另一個頁面。有關這種情況的細節,請參見:Passing Server Control Values Between Pages。