Stats:GetTotalMemoryUsageMb() and Stats:GetMemoryUsageMbForTag() are contradictory

I am trying to debug memory usage and get an idea of how memory usage changes over time (and also compare arbitrary the total usage of an arbitrary selection of labels). However the two different Stats service method calls are providing contradictory information (at least on the desktop client, mobile client seems to behave differently):

  1. Stats:GetTotalMemoryUsageMb() is always smaller than the sum of Stats:GetMemoryUsageMbForTag() over all Enum.DeveloperMemoryTag enums.
  2. At least one memory category (“Internal”) is able to have memory usage higher than the value returned by Stats:GetTotalMemoryUsageMb().

For example, here is a screenshot of a custom memory UI in a fresh live server of a game I am working on:

0_TOTAL_API displays the memory usage returned by Stats:GetTotalMemoryUsageMb()
1_TOTAL_SUM displays the sum of the memory usages of the tags displayed in the list under it ([01] to [15]).

(Note that the screenshot is truncated; other tags are present in the list but their values are very small.)

You can see that API call gives a result that is half of the sum, which is a pretty massive difference. You can also see that the “Internal” category is using more memory than what the API call says the entire game is using.

The most likely explanations I can think of for this issue is that there are some categories whose memory usages overlap with each other, and that Stats:GetTotalMemoryUsageMb() isn’t actually providing the full memory usage. However these caveats are not documented so I don’t know whether this behavior is intentional or a bug.

Quick code for reproduction in an empty place file:

game:GetService("ContextActionService"):BindAction("Print Memory", function(_, State)
	if State == Enum.UserInputState.Begin then
		local Stats = game:GetService("Stats")
		local TotalAPI = Stats:GetTotalMemoryUsageMb()
		local TotalSum = 0
		for _, Tag in ipairs(Enum.DeveloperMemoryTag:GetEnumItems()) do
		   TotalSum += Stats:GetMemoryUsageMbForTag(Tag)
		end
		print("Total API:", TotalAPI)
		print("Total Sum:", TotalSum)
	end
end, true, Enum.KeyCode.M)

Client Version: 0.572.0.5720484 (3f368f)

Expected behavior

Ideally, Stats:GetTotalMemoryUsageMb() should agree with the sum of Stats:GetMemoryUsageMbForTag() over all Enum.DeveloperMemoryTag enums. If that behavior is not a bug, then it should be documented, along with a description of the affected labels (if not all of them) or any other relevant information.

3 Likes

Thanks for the report! We’ve filed a ticket in our internal database.

1 Like

Hello!

My apologies for updating this ancient thread.

Memory allocations should only be categorized in exactly one category, so there should not be any overlap resulting in this discrepancy.

This discrepancy is most likely due to a difference in accounting. When we allocate heap memory in the Engine, we track the category we allocated it against, then later subtract the value later when the memory is freed. However, the Stats:GetTotalMemoryUsageMb() API actually reads memory used from the operating system’s point of view, which may not include e.g. memory that has been paged out to disk. On Windows specifically, we call GetProcessMemoryInfo and return the Working Set Size that this API provides. According to Microsoft’s documentation, this API does exclude paged memory. (“The working set of a process is the set of pages in the virtual address space of the process that are currently resident in physical memory.” – paged memory is not resident.)

My apologies for the long explanation, but the short version is that these two APIs are measuring different things.

Thanks!

2 Likes

In that case, can a brief note about that be added to the docs? Stats | Documentation - Roblox Creator Hub

Definitely, I added a paragraph to that method.

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.