Search code examples
c#asp.netmemory-leakspomelo-entityframeworkcore-mysql

memory leak in a c# api


Even with a very simple request my c# api gets filled with unnecessary byte[] strings etc. and i really can't find anywhere where i think there can be a memory leak.

a little description:
The method collects all notebooks from a user and returns them. It recognizes the user by the BearerToken.

Here is the code that is called, and yet per request several kb more ram is consumed and never released:

GetCurrentUser:

public static async Task<UserModel?> GetCurrentUser(DataBaseContext _db, string bearerToken)
{
    //get from the bearer token the username
    //create jwt token
    var token = new JwtSecurityToken(jwtEncodedString: bearerToken);

    //get the expiry from the token
    var userName = token.Claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier)?.Value;

    //get the whole user form the db
    var user = _db.User
        .Include(x => x.Invoices)
        .Include(x => x.Notebook)
        .Include(x => x.Logins)
        .FirstOrDefaultAsync(x => x.Username == userName);

    return await user;
}

GetCurrentUser & GetAll

private async Task<UserModel?> GetCurrentUser()
{
    // Get the bearer token from the header
    var bearerToken = HttpContext.Request.Headers["bearerToken"].ToString();
    var user = await UserCore.GetCurrentUser(_db, bearerToken);
    return user;
}

[HttpGet]
[Route("GetAll")]
public async Task<IActionResult> GetAll()
{
    //set the users traceId
    Guid traceId = Guid.NewGuid();
            
    //get the user
    var user = await GetCurrentUser();
    if (user == null)
        return new BadRequestObjectResult(ResponseMgr.CreateResponse(400, traceId, "The user does not exist"));

    //get all notes
    var notes = user.Notebook.ToList();
    
    //return all notes
    return new OkObjectResult(ResponseMgr.CreateResponse(200, traceId, "All notes", new Dictionary<string, object> { { "notes", notes } }));
}

this is the heapmap:
mem usage

heapmap

this is one of the things i don't understand, this is the list with "duplicate strings", first column says "value", second "wasted" and third "count" and at the bottom "total"

The thing is, the emojis are content/value of one the notebook, but why does it keep the data and not release them after the request, so to sum up I found the leak but not where it happens. double chars

All in one, I can't find the location, and if I make the request 50 times, then the API consumes several MB of ram and they will release the even the GC can't do that.


Solution

    1. your code have another problem too. when username null, not need check it the query for null member just need forexample return it the null

    2. you use more .Include(), If one of them is a large amount of data, you will have problems (you return List items, try take there data with another and better query )

    3. use AsNoTracking()

      means:

    returns a new query and the entities aren't saved in cache, means that doesn't have tracking, the queries will read from database origin but won't saved in the context