自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Linux系列:如何用C#調(diào)用C方法造成內(nèi)存泄露

開發(fā) 前端
在 windows 平臺上,我們常常在 C++ 代碼中用 extern "C"? 導(dǎo)出 C風(fēng)格 的函數(shù),然后在 C# 中用 DllImport 的方式引入,那在 Linux 上怎么玩的?

一、背景 

1. 講故事

今年準備多寫一點 Linux平臺上的東西,這篇從 C# 調(diào)用 C 這個例子開始。在 windows 平臺上,我們常常在 C++ 代碼中用 extern "C" 導(dǎo)出 C風(fēng)格 的函數(shù),然后在 C# 中用 DllImport 的方式引入,那在 Linux 上怎么玩的?畢竟這對研究 Linux 上的 C# 程序非托管內(nèi)存泄露有非常大的價值,接下來我們就來看下。

二、一個簡單的非托管內(nèi)存泄露 

1. 構(gòu)建 so 文件

在 Windows 平臺上我們會通過 MSVC 編譯器將 C代碼編譯出一個成品 .dll,在 Linux 上通常會借助 gcc 將 c 編譯成 .so 文件,這個.so 全稱 Shared Object,為了方便講解,先上一段簡單的代碼:

#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>

#define BLOCK_SIZE (10 * 1024)              // 每個塊 10K
#define TOTAL_SIZE (1 * 1024 * 1024 * 1024) // 總計 1GB
#define BLOCKS (TOTAL_SIZE / BLOCK_SIZE)    // 計算需要的塊數(shù)

void heapmalloc()
{
    uint8_t *blocks[BLOCKS]; // 存儲每個塊的指針

    // 分配 1GB 內(nèi)存,分成多個小塊
    for (size_t i = 0; i < BLOCKS; i++)
    {
        blocks[i] = (uint8_t *)malloc(BLOCK_SIZE);
        if (blocks[i] == NULL)
        {
            printf("內(nèi)存分配失??!\n");
            return;
        }

        // 確保每個塊都被實際占用
        memset(blocks[i], 20, BLOCK_SIZE);
    }

    printf("已經(jīng)分配 1GB 內(nèi)存在堆上!\n");
}

接下來使用 gcc 編譯,參考如下:

gcc -shared -o libmyleak.so -fPIC myleak.c
  • -shared: 編譯成共享庫
  • -fPIC:   指定共享庫可以在內(nèi)存任意位置被加載(地址無關(guān)性)

命令執(zhí)行完之后,就可以看到一個 .so 文件了,截圖如下:

圖片圖片

最后可以用 nm 命令驗證下 libmyleak.so 中是否有 Text 段下的 heapmalloc 導(dǎo)出函數(shù)。

root@ubuntu2404:/data2/c# nm libmyleak.so
0000000000004028 b completed.0
                 w __cxa_finalize@GLIBC_2.2.5
00000000000010c0 t deregister_tm_clones
0000000000001130 t __do_global_dtors_aux
0000000000003e00 d __do_global_dtors_aux_fini_array_entry
0000000000004020 d __dso_handle
0000000000003e08 d _DYNAMIC
000000000000125c t _fini
0000000000001170 t frame_dummy
0000000000003df8 d __frame_dummy_init_array_entry
00000000000020f8 r __FRAME_END__
0000000000003fe8 d _GLOBAL_OFFSET_TABLE_
                 w __gmon_start__
000000000000203c r __GNU_EH_FRAME_HDR
0000000000001179 T heapmalloc
0000000000001000 t _init
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
                 U malloc@GLIBC_2.2.5
                 U memset@GLIBC_2.2.5
                 U puts@GLIBC_2.2.5
00000000000010f0 t register_tm_clones
                 U __stack_chk_fail@GLIBC_2.4
0000000000004028 d __TMC_END__

2. C# 代碼調(diào)用

so構(gòu)建好了之后,后面就比較好說了,使用 dotnet new console -n CSharpApplication --use-program-main true 新建一個CS項目。

root@ubuntu2404:/data2/csharp# dotnet new console -n CSharpApplication --use-program-main true
The template "Console App" was created successfully.

Processing post-creation actions...
Restoring /data2/csharp/CSharpApplication/CSharpApplication.csproj:
  Determining projects to restore...
  Restored /data2/csharp/CSharpApplication/CSharpApplication.csproj (in 1.7 sec).
Restore succeeded.

編譯下 C# 項目,然后將 libmyleak.so 放到 C#項目的 bin目錄,修改 C# 代碼如下:

using System.Runtime.InteropServices;

namespaceCSharpApplication;

classProgram
{
    [DllImport("libmylib.so", CallingConvention = CallingConvention.Cdecl)]
    public static extern void hello();

    static void Main(string[] args)
    {
        hello();
        Console.ReadLine();
    }
}

最后用 dotnet CSharpApplication.dll 運行:

root@ubuntu2404:/data2/csharp/CSharpApplication/bin/Debug/net8.0# dotnet CSharpApplication.dll
已經(jīng)分配 1GB 內(nèi)存在堆上!

程序是跑起來了,那真的是吃了1G呢? 可以先用 htop 觀察程序,從截圖看沒毛病。

圖片圖片

那這 1G 真的在 heap 上嗎? 可以用 maps 觀察。

root@ubuntu2404:~# ps -ef | grep CSharp
root       10764   10730013:35 pts/21   00:00:00 dotnet CSharpApplication.dll
root       11049   11027013:41 pts/22   00:00:00 grep --color=auto CSharp

root@ubuntu2404:~# cat /proc/10764/maps
614e1f592000-614e1f598000 r--p 0000000008:021479867                    /usr/lib/dotnet/dotnet
614e1f598000-614e1f5a4000 r-xp 0000500008:021479867                    /usr/lib/dotnet/dotnet
614e1f5a4000-614e1f5a5000 r--p 0001000008:021479867                    /usr/lib/dotnet/dotnet
614e1f5a5000-614e1f5a6000 rw-p 0001000008:021479867                    /usr/lib/dotnet/dotnet
614e5b5d9000-614e9b8a8000 rw-p 0000000000:000                          [heap]
...


root@ubuntu2404:~# pmap 10764
10764:   dotnet CSharpApplication.dll
0000614e1f592000     24K r---- dotnet
0000614e1f598000     48K r-x-- dotnet
0000614e1f5a4000      4K r---- dotnet
0000614e1f5a5000      4K rw--- dotnet
0000614e5b5d9000 1051452K rw---   [ anon ]
...

根據(jù) linux 進程的內(nèi)存布局,可執(zhí)行image之后是 heap 堆,可以看到 [heap] 約等于1G (614e9b8a8000 - 614e5b5d9000),即 pmap 中的 1051452K。

三、總結(jié) 

部署在 Linux上的.NET程序同樣存在 非托管內(nèi)存泄露的問題,這篇文章的例子雖然很簡單,希望能給大家?guī)硪恍┧伎己陀^測途徑吧。

責(zé)任編輯:武曉燕 來源: 一線碼農(nóng)聊技術(shù)
相關(guān)推薦

2009-08-28 10:14:45

C#內(nèi)存泄露

2009-08-31 18:05:14

C#調(diào)用WalkTre

2009-08-31 16:33:28

C#調(diào)用Dispose

2009-09-01 11:04:59

C#調(diào)用擴展方法

2009-08-03 12:57:27

C#調(diào)用DLL

2009-08-20 10:53:23

C#操作內(nèi)存

2009-09-11 10:59:06

Effective C調(diào)用Dispose()

2011-04-08 09:52:44

C++C#DLL

2009-08-24 15:58:00

Visual C#生成

2009-08-05 09:30:39

C#調(diào)用DLL函數(shù)

2009-08-26 16:58:12

調(diào)用C# Thread

2009-09-02 10:49:46

C#調(diào)用析構(gòu)方法

2009-08-05 09:40:02

C#調(diào)用DLL函數(shù)

2015-04-02 16:23:50

C++內(nèi)存泄露檢查

2009-08-17 16:18:47

C#調(diào)用CreateO

2009-08-05 16:29:18

C#調(diào)用C++動態(tài)鏈接

2009-08-20 16:07:39

C#和ADO.NET訪

2009-08-17 15:34:58

C#創(chuàng)建XML

2009-08-11 11:07:49

Java調(diào)用C# we

2024-05-16 12:33:37

C#編程指針
點贊
收藏

51CTO技術(shù)棧公眾號