Vấn đề về bộ nhớ của Com object trong C#
TIL
594
C#
18
Male avatar

LLT viết ngày 22/11/2016

Vấn đề về bộ nhớ của Com object trong C

  1. Vấn đề gặp phải

    • Mình cần viết một tool xử lý vài thứ nằm trong file excel
    • Quái nào C# có bộ GC ngon vậy mà mem cứ tăng mãi.
    • Bật process lên thì ôi thôi từ đầu đến cuối các process excel nhiều vãi.
  2. Nguyên nhân

    • Do com object là loại unmanaged memory nên nó không được release
  3. Vậy phải làm thế nào?
    Nói chung là chỉ cần dùng Marshal Class thôi. Cụ thể cách dùng như dưới đây:

  class Program
    {        
        static void Main(string[] args)
        {
            Application app = new Application();
            Workbook workbook = app.Workbooks.Open("test.xlsx");
            workbook.Close();
            app.Quit();
            Marshal.FinalReleaseComObject(workbook);
            Marshal.FinalReleaseComObject(app);
            Console.ReadKey();
        }
    }

Về mặt cơ bản, cách trên là được. Tuy nhiên bạn hãy tưởng tượng rằng 1 chương trình mà có rất nhiều đoạn open rồi close rồi release kiểu này sẽ hơi tốn công một chút. Tại sao ta không sửa đổi 1 chút nhìn cho hay ho thêm nhỉ

    class LTTExcel
    {
        private Application app = null;
        Workbook workbook = null;
        public void Load(string path)
        {
            try
            {
                app = new Application();
                workbook = app.Workbooks.Open(path);
            }
            catch
            {
                throw;
            }
            finally
            {
                Dispose();
            }

        }
        private void Dispose()
        {
            if(workbook != null)
            {
                workbook.Close();
            }
            if(app != null)
            {
                app.Quit();
            }
            Marshal.FinalReleaseComObject(workbook);
            Marshal.FinalReleaseComObject(app);
        }
    }
    class Program
    {        
        static void Main(string[] args)
        {
            LTTExcel excel = new LTTExcel();
            excel.Load("test.xlsx");
        }
    }

Về mặt bản chất thì cách thứ 2 này cũng không khác cách thứ nhất là mấy. Nó đảm bảo cho người khác sử dụng class LTTExcel không cần để ý đến việc giải phóng com object. Tuy nhiên cứ thêm logic nào trong class LTTExcel lại phải đưa hàm Dispose vào. Đến đây chắc các bạn sẽ suy nghĩ là sao không thay đổi hàm Dispose kia để người nào dùng LTTExcel tự giải phóng lấy object của họ. Tuyệt vời đây là một ý tưởng rất hay. Tuy nhiên mình vốn là con người nên việc mình quên gọi hàm Dispose cũng khá thường xuyên xảy ra. Mình thay đổi một chút để giảm thiêu cái việc quên này.

    class LTTExcel : IDisposable
    {
        private Application app = null;
        Workbook workbook = null;
        private bool isDisposed = false;
        public void Load(string path)
        {
            app = new Application();
            workbook = app.Workbooks.Open(path);
        }   
        public void Dispose()
        {
            Dispose(true);
            GC.Collect();
            GC.WaitForPendingFinalizers();
        }
        private void Dispose(bool disposing)
        {
            if(isDisposed)
            {
                return;
            }
            if (disposing)
            {
                if (workbook != null)
                {
                    workbook.Close();
                }
                if (app != null)
                {
                    app.Quit();
                }
                Marshal.FinalReleaseComObject(workbook);
                Marshal.FinalReleaseComObject(app);
                isDisposed = true;
            }
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            using (LTTExcel excel = new LTTExcel())
            {
                excel.Load("test.xlxs");
            }
        }
    }

Mình xinh tổng kết lại như dưới đây:

  • Nếu dùng Com object thì phải dùng Marshal class để giải phóng bộ nhớ không được quản lý
  • Nên sử dụng IDisposable và using statement

LLT 22-11-2016

Bình luận


White
{{ comment.user.name }}
Bỏ hay Hay
{{comment.like_count}}
Male avatar
{{ comment_error }}
Hủy
   

Hiển thị thử

Chỉnh sửa

Male avatar

LLT

4 bài viết.
0 người follow
Kipalog
{{userFollowed ? 'Following' : 'Follow'}}
Cùng một tác giả
Male avatar
2 0
Tạo file với nội dung như dưới Path: /etc/systemd/system/dockertcp.socket Unit] Description=Docker Socket for the API Socket] ListenStream=237...
LLT viết 9 tháng trước
2 0
Male avatar
1 0
Extension method in C 1. Là gì? Mở rộng của 1 class có sẵn nào đó 2. Dùng như nào Là thành phần của 1 static method Method có ít nhất 1 tha...
LLT viết hơn 1 năm trước
1 0
Male avatar
1 0
Laravel and Docker Môi trường hiện có MacOS: 10.12 Laravel: 5.4 MySQL: 5.7 Hiện trạng môi trường hiện có Do từ đầu dùng local để dev nên...
LLT viết 1 năm trước
1 0
Bài viết liên quan
White
0 2
fCC: Technical Documentation Page note So I have finished the HTML part of this exercise and I want to come here to lament about the lengthy HTML ...
HungHayHo viết 1 tháng trước
0 2
White
19 1
Toán tử XOR có tính chất: + A XOR A = 0 + 0 XOR A = A Với tính chất này, có thể cài đặt bài toán sau với độ phức tạp O(N) về runtime, và với O(1)...
kiennt viết gần 2 năm trước
19 1
White
1 1
Chào mọi người, hôm nay mình viết một bài TIL nhỏ về cách lấy độ phân giải của màn hình hiện tại đang sử dụng. xdpyinfo | grep dimensions Kết quả...
namtx viết 12 tháng trước
1 1
{{like_count}}

kipalog

{{ comment_count }}

bình luận

{{liked ? "Đã kipalog" : "Kipalog"}}


Male avatar
{{userFollowed ? 'Following' : 'Follow'}}
4 bài viết.
0 người follow

 Đầu mục bài viết

Vẫn còn nữa! x

Kipalog vẫn còn rất nhiều bài viết hay và chủ đề thú vị chờ bạn khám phá!