在 JScript 中释放内存、批量加载问题及其他更新日期: 1/24/2005Nancy Michell 编辑
问:我有一些关于 JScript® 中垃圾回收的问题。我认为在 Microsoft® Internet Explorer 6.0 中有内存泄漏,但在另一方面,它可能是循环引用问题。在我的代码中,我假设“new Object()”属于 JScript,而“document.createElement”属于 Internet Explorer DOM,因此 JScript 中的垃圾回收器无法释放 DOM 元素。这正确吗?避免这一问题的最佳方法是什么呢?当您将代码加载到 Internet Explorer 6.0 中并单击“Refresh”时,您可以在“Task Manager”中观察到内存增加:
答:这不是内存泄漏。您正在页面上创建新文本一千次!这会使页面变大。如果您创建了许多无法获得也无法释放的对象,那才是内存泄漏。在这里,您将创建许多元素,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 中所示的箭头符号都是有方向的,因此它们的解释依赖于它们所放的位置。文本是没有方向的,因此它与您决定将它放在哪里无关;意思也不会变化。
然而研究表明,自报告的用户首选是一个按钮而不是其他内容,这并不比第一次遇见时理解界面更重要。对于只是偶然使用的工具或 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 代码如下:
答:对不起,没有方法可以检测调用方是否会捕获您引发的异常。然而,您的问题暴露了您应用程序中的一个潜在设计缺陷。引发异常的所有点都说“发生了意外情况,但我不知道如何处理它”。如果您可以不用再次引发该异常就离开,则很显然,您可以处理这种意外事件。如果您可以处理它并继续,则就不需要再次引发异常。如果您无法处理它,则请顺从您的调用方来处理它。您不应该根据调用方可以处理什么来进行决定,而应该根据您可以处理什么来进行决定。
如果没有调用方可以处理该异常,则正确的做法是停止程序。无法处理意外的程序会遭到极大的破坏,并且在它进行破坏之前必须停止它。如果您的调用方无法处理异常,则要么重新编写调用方,要么不引发异常。
此外,不要总是使用异常作为主要情况的控制流。异常处理被专门设计和实现为管理致命错误,因此这就是它应该用于的全部方面。
问:在 ASP.NET(特别是结合了 Visual Basic)中,您如何将窗体数据传递给网页?当呈现 ASP.NET 网页时,窗体的操作字段会自动更改以传递给它自己。我需要显示登录页面,并且当用户单击“Login”时,可将窗体数据传递到其他网站(所建立的网站使用 Request.Form 来捕获我的数据)。我知道我可以自己捕获数据,并将它传入查询字符串中,但是这不可选。我必须将它传递给其他网站。
答:如果您在窗体上只使用 HTMLControl,则您将它传递到另一个页面所需要做的就是从 FORM 标记中删除 runat="server",并将操作属性设置为您需要传递到的 URL。如果您不添加 runat="server",则会将 FORM 元素发送到不变的客户端。这不会妨碍您在 Web 窗体的 Page_Load 事件中设置窗体上的 HTMLControl 值。
如果您使用 WebControl,则在窗体上需要 runat="server"。然而,您仍然可以传递到另一个页面。有关这种情况的细节,请参见:Passing Server Control Values Between Pages。