Feeds:
文章
留言

Archive for 六月 10th, 2008

try…finally 的一個用途

今天看到一篇"Finally, the alternative fix for IE6’s memory leak is available"探討 IE6 記憶體洩漏的好文章,其中談到利用 try…finally 解決記憶體洩漏的問題,我簡單描述一下他的作法,如下:

function createButton() {
  var obj = document.createElement("button");
  obj.innerHTML = "click me";
  obj.onclick = function() {
    //handle onclick
  }
  obj.onmouseover = function() {
    //handle onmouseover
  }

  //this helps to fix the memory leak issue
  try {
    return obj;

  } finally {
    obj = null;
  }

}

一般的寫法會導致 obj 仍然 Reference 到記憶體,倒置 IE6 最後仍然無法釋放這塊記憶體,解法就是將 obj 設定為 null,可是,一般函數遇到 return 敘述就返回沒有辦法執行 obj=null 敘述。此時作者將 try…finally 用在這個不常見的地方,透過 finally 一定會執行的語言規則。將 return 放置在 try 區段,obj = null 放在 finally 一定會執行區段,來解決 IE6 記憶體洩漏的問題。

這樣的寫法讓我想起了 VB 的 Function 寫法,VB 的執行結果是透過 FunctionName = ReturnValue 方式來回傳,但是執行這個敘述並不會馬上返回函數呼叫點,而是執行到整個 Function 結束或是 Exit Function。因此,其他諸如 Javascript, C++, C# 都可用這個方式模擬 VB 函數回傳寫法。

假如有一個 VB 程序如下:

Public Sub PrintLine(ByRef msg As String)
    Debug.Print (msg)
End Sub

Public Function MyCalc(ByVal value As Integer) As Integer
    PrintLine "MyCalc before"
    MyCalc = value * 2
    PrintLine "MyCalc After"
End Function

Sub main()
    PrintLine "Before"
    MyCalc 2
    PrintLine "After"
End Sub

執行結果

Before
MyCalc before
MyCalc After
After

要透過 try..finally 模擬類似的語法,我嘗試用幾個目前常用的工具來實作

C++ Builder 6.0 測試

#include <vcl.h>
#include <string>
#include <iostream>
#pragma hdrstop

//—————————————————————————
int PrintLine(std::string msg){
    std::cout << msg << std::endl;
}

int MyCalc(int value){
    PrintLine("MyCalc before");
    try{
        return value*2;
    }__finally{
        PrintLine("MyCalc after");
    }
}
#pragma argsused
int main(int argc, char* argv[])
{
    PrintLine("before");
    MyCalc(2);
    PrintLine("after");
    return 0;
}

VC8 測試

#include "stdafx.h"
#include <iostream>
//—————————————————————————
void PrintLine(const char* msg){
    std::cout << msg << std::endl;
}

int MyCalc(int value){   
    PrintLine("MyCalc Before");
    __try{       
        return value*2;
    }__finally{
        PrintLine("MyCalc After");
    }

}

int main(int argc, char* argv[])
{
    PrintLine("Beforen");
    MyCalc(2);
    PrintLine("Aftern");
    return 0;
}

C# 測試

using System;

namespace ConsoleApplication1 {
    class Program {
        static void PrintLine(String msg){
            Console.WriteLine(msg);
        }

        static int MyCalc(int value) {           
            try {
                PrintLine("MyCalc before");
                return value*2;
            } finally {
                PrintLine("MyCalc After");
            }

        }
        static void Main(string[] args) {
            PrintLine( "Before");
            MyCalc(2);
            PrintLine("After");
        }
    }
}

總之對我而言是一個相當新穎的用法,未來應該有應用的地方。

Read Full Post »