成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Linux系列:如何用C#調用C方法造成內存泄露

開發 前端
在 windows 平臺上,我們常常在 C++ 代碼中用 extern "C"? 導出 C風格 的函數,然后在 C# 中用 DllImport 的方式引入,那在 Linux 上怎么玩的?

一、背景 

1. 講故事

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

二、一個簡單的非托管內存泄露 

1. 構建 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)    // 計算需要的塊數

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

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

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

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

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

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

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

圖片圖片

最后可以用 nm 命令驗證下 libmyleak.so 中是否有 Text 段下的 heapmalloc 導出函數。

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# 代碼調用

so構建好了之后,后面就比較好說了,使用 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
已經分配 1GB 內存在堆上!

程序是跑起來了,那真的是吃了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 ]
...

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

三、總結 

部署在 Linux上的.NET程序同樣存在 非托管內存泄露的問題,這篇文章的例子雖然很簡單,希望能給大家帶來一些思考和觀測途徑吧。

責任編輯:武曉燕 來源: 一線碼農聊技術
相關推薦

2009-08-28 10:14:45

C#內存泄露

2009-08-31 16:33:28

C#調用Dispose

2009-08-31 18:05:14

C#調用WalkTre

2009-09-01 11:04:59

C#調用擴展方法

2009-08-03 12:57:27

C#調用DLL

2009-08-20 10:53:23

C#操作內存

2009-08-24 15:58:00

Visual C#生成

2009-09-11 10:59:06

Effective C調用Dispose()

2009-08-26 16:58:12

調用C# Thread

2009-08-05 09:40:02

C#調用DLL函數

2009-09-02 10:49:46

C#調用析構方法

2009-08-05 09:30:39

C#調用DLL函數

2011-04-08 09:52:44

C++C#DLL

2015-04-02 16:23:50

C++內存泄露檢查

2009-08-17 16:18:47

C#調用CreateO

2025-05-08 03:33:00

Linuxperf.NET

2009-08-05 16:29:18

C#調用C++動態鏈接

2009-08-17 15:34:58

C#創建XML

2009-08-20 16:07:39

C#和ADO.NET訪

2024-05-16 12:33:37

C#編程指針
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国内精品久久久久 | 91精品国产91综合久久蜜臀 | 欧美日韩亚洲一区二区 | 91麻豆精品国产91久久久更新资源速度超快 | 日本精品一区二区三区在线观看视频 | 久久99精品久久久97夜夜嗨 | 国产精品久久久久久久久大全 | a视频在线 | 成人国产在线视频 | 日韩精品一区二区三区视频播放 | 亚洲伊人久久综合 | 波多野结衣在线观看一区二区三区 | 中文字幕福利 | 黄色一级大片在线免费看产 | 天天玩天天干天天操 | 成人免费av | 精产国产伦理一二三区 | 影音先锋中文字幕在线观看 | 久久精品网 | 二区成人 | 热99在线| 中文字幕av一区二区三区 | 日韩欧美在线一区 | 国产欧美精品一区二区 | 国产精品免费一区二区三区四区 | 亚洲精品二区 | 久久久久久国产 | 欧美国产一区二区三区 | 午夜男人视频 | 久久视频一区 | 人人看人人爽 | 久久久久久成人 | 孰女乱色一区二区三区 | 亚洲国产精品区 | 欧美极品一区二区 | 亚洲最大福利网 | 精品国产成人 | 欧美成人精品二区三区99精品 | 亚洲激情一级片 | 欧美视频免费在线 | 天天综合久久 |