查询mongoDB时,dotnet会分配大量内存

发布于 2025-01-20 19:01:28 字数 5861 浏览 1 评论 0原文

我的应用程序使用了很多内存,因为我经常查询数据库。我正在发布我的C#代码,希望有人能告诉我我在做什么错。我还使用Google GO语言创建了相同的程序,以比较内存使用量。 C#上的同一程序使用超过1 GB的内存,并且GO仅使用100MB。 C#在堆上创建了数千个分配,只有少数几个。最后,C#花了3秒钟的时间来编译发布模式,并且仅进行毫秒。

C#代码:

var mongoDb = new MongoClient("mongodb://localhost:27017").GetDatabase("MyTestDb");

var collection = mongoDb.GetCollection<Account>("Accounts");

// find all items on collection named Accounts
var items = collection.Find("{}").ToEnumerable();

int counter = 0;
foreach (var a in items)
    counter++;
Console.WriteLine(ctr2);


// I am naming my properties incorrectly just to make the code shorter and avoid having a converter
[BsonIgnoreExtraElements]
public class Account
{
    public string _id { get; set; }
    public string dateCreated{ get; set; }
    public string dateDeleted{ get; set; }
    public string dateUpdated{ get; set; }
    public string idCloudServicePbxFailover{ get; set; }
    public string idCloudServiceWebApp{ get; set; }
    public bool hasGrantedSupportAccess{ get; set; }
}

如果我使用profiler运行此代码,例如valgrind我会得到此结果:

==132531== HEAP SUMMARY:
==132531==     in use at exit: 96,284,945 bytes in 14,388 blocks
==132531==   total heap usage: 105,120 allocs, 90,732 frees, 177,448,116 bytes allocated
==132531== 
==132531== LEAK SUMMARY:
==132531==    definitely lost: 200 bytes in 8 blocks
==132531==    indirectly lost: 0 bytes in 0 blocks
==132531==      possibly lost: 42,416 bytes in 145 blocks
==132531==    still reachable: 96,242,329 bytes in 14,235 blocks
==132531==                       of which reachable via heuristic:
==132531==                         stdstring          : 41,313 bytes in 52 blocks
==132531==                         newarray           : 48 bytes in 1 blocks
==132531==         suppressed: 0 bytes in 0 blocks
==132531== Rerun with --leak-check=full to see details of leaked memory

如果我使用linux的time命令,我会得到此结果:

./bin/Release/net6.0/MyTestApp   7.48s  user 0.88s system 71% cpu 11.645 total
avg shared (code):         0 KB
avg unshared (data/stack): 0 KB
total (sum):               0 KB
max memory:                1867 MB
page faults from disk:     1
other page faults:         470073

最后,如果我运行<代码> HTOP 在Linux上我看到我的内存上升超过1 GB。

我无法将我的帐户类更改为struct,因为Mongo不支持结构。我希望做出这一更改,以减少内存分配。

无论如何,如果我运行了与Google一起使用相同操作的相同程序,这是结果:

GO代码:

package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "go.mongodb.org/mongo-driver/bson"
    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
    // "go.mongodb.org/mongo-driver/mongo/options"
    // "go.mongodb.org/mongo-driver/x/mongo/driver/mongocryp"
)

type Account struct {
    ID                        string `json:"_id,omitempty" bson:"_id,omitempty"`
    DateCreated               string `json:"dateCreated,omitempty" bson:"dateCreated,omitempty"`
    DateDeleted               string `json:"dateDeleted,omitempty" bson:"dateDeleted,omitempty"`
    DateUpdated               string `json:"dateUpdated,omitempty" bson:"dateUpdated,omitempty"`
    IdCloudServicePbxFailover string `json:"idCloudServicePbxFailover,omitempty" bson:"idCloudServicePbxFailover,omitempty"`
    IdCloudServiceWebApp      string `json:"idCloudServiceWebApp,omitempty" bson:"idCloudServiceWebApp,omitempty"`
    CompanyName               string `json:"CompanyName,omitempty" bson:"CompanyName,omitempty"`
    HasGrantedSupportAccess   bool   `json:"hasGrantedSupportAccess,omitempty" bson:"hasGrantedSupportAccess,omitempty"`
}

var client *mongo.Client

const conString = "mongodb://localhost:27017"
const dbName = "MyTestDb"
const colName = "Accounts"

var collection *mongo.Collection

func main() {
    fmt.Println("Testing mongo")
    clientOption := options.Client().ApplyURI(conString)

    client, err := mongo.Connect(context.Background(), clientOption)

    if err != nil {
        log.Fatal(err)
    }
    fmt.Println("MongoDB connected")

    if client == nil {
        fmt.Println("foooo")
    }

    ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)

    // cursor, err := client.Database(dbName).Collection(colName).Find(ctx, bson.D{{"dateCreated", bson.D{{"$gt", "2020"}}}})
    cursor, err := client.Database(dbName).Collection(colName).Find(ctx, bson.M{})
    if err != nil {
        log.Fatal(err)
    }
    defer cursor.Close(ctx)

    ctr := 0
    for cursor.Next(ctx) {

        ctr++
        var acc Account
        cursor.Decode(&acc)
        // if acc.ID == "96e0a7f6-5b6d-4a10-9b3d-c5d8275fdb1f" {
        //  break
        // }
    }

    fmt.Println(ctr)
}

这是valgrim输出:

==135050== HEAP SUMMARY:
==135050==     in use at exit: 2,016 bytes in 7 blocks
==135050==   total heap usage: 15 allocs, 8 frees, 2,240 bytes allocated
==135050== 
==135050== LEAK SUMMARY:
==135050==    definitely lost: 0 bytes in 0 blocks
==135050==    indirectly lost: 0 bytes in 0 blocks
==135050==      possibly lost: 2,016 bytes in 7 blocks
==135050==    still reachable: 0 bytes in 0 blocks
==135050==         suppressed: 0 bytes in 0 blocks
==135050== Rerun with --leak-check=full to see details of leaked memory

这是time ./mongodb--去

./mongodb-go   4.99s  user 0.44s system 72% cpu 7.463 total
avg shared (code):         0 KB
avg unshared (data/stack): 0 KB
total (sum):               0 KB
max memory:                100 MB
page faults from disk:     0
other page faults:         21916

My application is using a lot of memory because I am querying my database a lot. I am posting my C# code hoping someone can tell me what am I doing wrong. I have also created the same program using Google Go language in order to compare memory usage. The same program on C# uses over 1 GB of memory and Go only uses 100MB. C# creates thousands of allocations on the heap and Go only a few. Lastly C# took 3 seconds to compile on release mode and Go only milliseconds.

C# code:

var mongoDb = new MongoClient("mongodb://localhost:27017").GetDatabase("MyTestDb");

var collection = mongoDb.GetCollection<Account>("Accounts");

// find all items on collection named Accounts
var items = collection.Find("{}").ToEnumerable();

int counter = 0;
foreach (var a in items)
    counter++;
Console.WriteLine(ctr2);


// I am naming my properties incorrectly just to make the code shorter and avoid having a converter
[BsonIgnoreExtraElements]
public class Account
{
    public string _id { get; set; }
    public string dateCreated{ get; set; }
    public string dateDeleted{ get; set; }
    public string dateUpdated{ get; set; }
    public string idCloudServicePbxFailover{ get; set; }
    public string idCloudServiceWebApp{ get; set; }
    public bool hasGrantedSupportAccess{ get; set; }
}

If I run this code with a profiler like valgrind I get this result:

==132531== HEAP SUMMARY:
==132531==     in use at exit: 96,284,945 bytes in 14,388 blocks
==132531==   total heap usage: 105,120 allocs, 90,732 frees, 177,448,116 bytes allocated
==132531== 
==132531== LEAK SUMMARY:
==132531==    definitely lost: 200 bytes in 8 blocks
==132531==    indirectly lost: 0 bytes in 0 blocks
==132531==      possibly lost: 42,416 bytes in 145 blocks
==132531==    still reachable: 96,242,329 bytes in 14,235 blocks
==132531==                       of which reachable via heuristic:
==132531==                         stdstring          : 41,313 bytes in 52 blocks
==132531==                         newarray           : 48 bytes in 1 blocks
==132531==         suppressed: 0 bytes in 0 blocks
==132531== Rerun with --leak-check=full to see details of leaked memory

If I use the time command from Linux I get this result:

./bin/Release/net6.0/MyTestApp   7.48s  user 0.88s system 71% cpu 11.645 total
avg shared (code):         0 KB
avg unshared (data/stack): 0 KB
total (sum):               0 KB
max memory:                1867 MB
page faults from disk:     1
other page faults:         470073

Lastly if I run htop on Linux I see that my memory goes up more than 1 GB.

I cannot change my Account class to a struct because Mongo does not support structs. I was hoping to make this change in order to reduce memory allocations.

Anyways if I run the same program that does the same thing with Go from Google this are the results:

Go code:

package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "go.mongodb.org/mongo-driver/bson"
    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
    // "go.mongodb.org/mongo-driver/mongo/options"
    // "go.mongodb.org/mongo-driver/x/mongo/driver/mongocryp"
)

type Account struct {
    ID                        string `json:"_id,omitempty" bson:"_id,omitempty"`
    DateCreated               string `json:"dateCreated,omitempty" bson:"dateCreated,omitempty"`
    DateDeleted               string `json:"dateDeleted,omitempty" bson:"dateDeleted,omitempty"`
    DateUpdated               string `json:"dateUpdated,omitempty" bson:"dateUpdated,omitempty"`
    IdCloudServicePbxFailover string `json:"idCloudServicePbxFailover,omitempty" bson:"idCloudServicePbxFailover,omitempty"`
    IdCloudServiceWebApp      string `json:"idCloudServiceWebApp,omitempty" bson:"idCloudServiceWebApp,omitempty"`
    CompanyName               string `json:"CompanyName,omitempty" bson:"CompanyName,omitempty"`
    HasGrantedSupportAccess   bool   `json:"hasGrantedSupportAccess,omitempty" bson:"hasGrantedSupportAccess,omitempty"`
}

var client *mongo.Client

const conString = "mongodb://localhost:27017"
const dbName = "MyTestDb"
const colName = "Accounts"

var collection *mongo.Collection

func main() {
    fmt.Println("Testing mongo")
    clientOption := options.Client().ApplyURI(conString)

    client, err := mongo.Connect(context.Background(), clientOption)

    if err != nil {
        log.Fatal(err)
    }
    fmt.Println("MongoDB connected")

    if client == nil {
        fmt.Println("foooo")
    }

    ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)

    // cursor, err := client.Database(dbName).Collection(colName).Find(ctx, bson.D{{"dateCreated", bson.D{{"$gt", "2020"}}}})
    cursor, err := client.Database(dbName).Collection(colName).Find(ctx, bson.M{})
    if err != nil {
        log.Fatal(err)
    }
    defer cursor.Close(ctx)

    ctr := 0
    for cursor.Next(ctx) {

        ctr++
        var acc Account
        cursor.Decode(&acc)
        // if acc.ID == "96e0a7f6-5b6d-4a10-9b3d-c5d8275fdb1f" {
        //  break
        // }
    }

    fmt.Println(ctr)
}

This is valgrim output:

==135050== HEAP SUMMARY:
==135050==     in use at exit: 2,016 bytes in 7 blocks
==135050==   total heap usage: 15 allocs, 8 frees, 2,240 bytes allocated
==135050== 
==135050== LEAK SUMMARY:
==135050==    definitely lost: 0 bytes in 0 blocks
==135050==    indirectly lost: 0 bytes in 0 blocks
==135050==      possibly lost: 2,016 bytes in 7 blocks
==135050==    still reachable: 0 bytes in 0 blocks
==135050==         suppressed: 0 bytes in 0 blocks
==135050== Rerun with --leak-check=full to see details of leaked memory

and here is the output of time ./mongodb-go:

./mongodb-go   4.99s  user 0.44s system 72% cpu 7.463 total
avg shared (code):         0 KB
avg unshared (data/stack): 0 KB
total (sum):               0 KB
max memory:                100 MB
page faults from disk:     0
other page faults:         21916

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文