-
Notifications
You must be signed in to change notification settings - Fork 17.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
runtime: MemStats.HeapReleased vs MemStats.HeapReacquired #32284
Comments
/cc @aclements @randall77 |
The current accounting is a bit weird and the docs aren't the best, I agree. HeapReleased is the portion of HeapIdle that has been given back to the OS. It can go up and down as the runtime allocates and frees objects. So HeapReleased is not a "total over the lifetime of the process" thing like TotalAlloc. It will always be the case that HeapReleased <= HeapIdle. Hopefully both should go towards zero when the application is in the midst of an allocation spree. Maybe we should replace the first sentence with this:
And maybe also (maybe higher up, when describing idle spans)
|
@randall77 what about making |
We don't want to redefine what existing fields mean. That would break existing users who have figured out what they mean. Is there particular information the current setup prevents you from getting? |
I'm currently unable to tell what becomes of the idle memory. Unless I'm missing something we can't tell apart the amounts of memory going back to heap to those which are returning to the system. I understand that would be a breaking change however I think the name is misleading and I think it cannot be exploited as it. If you don't want to change |
Just so I understand, you're wondering what fraction of bytes that become HeapIdle go through the state HeapReleased before transitioning back to a used state (HeapInuse or StackInuse) vs. go from HeapIdle to a used state directly? Or maybe it's something else? And I guess a follow on, why do you need this data? What decisions are you making based on the answers you get?
Yes, we could do that if it turns out to be necessary. |
Transitioning some apps from go 1.11 to go 1.12 I had troubles with docker containers being OOM Killed by kubernetes (not by the kernel) because their memory usage was only growing according to It turns out this was due to go 1.12 using To investigate this I took a look at the metrics exported by the client_golang library of prometheus which exposes the values of So I'm proposing to have counters tracking the total memory size that transitions:
With such counters I would have been able to quickly determine that my apps were indeed releasing memory to the system and that the problem was lying elsewhere. If |
Could you describe more about this? Why wasn't it obvious from just a large value of HeapReleased? That is, if you're getting killed at 1GB, and HeapInuse is 100MB and both HeapIdle and HeapReleased are 900MB, then it would be pretty clear that the issue was with the release mechanism not working. (If on the other hand HeapIdle were 900MB and HeapReleased was 0, then the issue would be that the scavenger isn't releasing pages promptly.) |
Here a graph of a pod that consumes lot of memory which is running At one point most of the |
Here another graph showing the same pod running I've added a purple dashed line which shows how the system see the memory consumption of the pod (metric coming from cAdvisor). The cAdvisor metric proves that the memory is actually being returned to the system but I don't understand why |
That's the way it is supposed to work. When you free memory, it becomes HeapIdle. It will stay in HeapIdle indefinitely unless your application does more allocation that needs that memory. Another way to look at it is that HeapIdle is a measure of virtual memory space. That virtual memory is only backed by physical pages for HeapIdle-HeapReleased. |
One unfortunate property of MemStats is that some fields are exclusive with each other, while others are subsets. I tried to spell this out in prose when I wrote the current documentation, but maybe we should document it more explicitly? It would look something like
I'm not quite sure how to clearly document which fields cover their parent and which don't. For example, HeapSys = HeapInUse + HeapIdle, but HeapIdle = HeapReleased + X, and there's no field for X. Maybe we should add a field for X? (I wish it had been HeapSys = HeapInUse + HeapIdle + HeapReleased, but we can't change that now.) |
You mean when a span has no more objects it's considered HeapIdle ?
Does that mean that HeapIdle memory is still allocated to the process whether it is backed by physical pages or not ? |
@aclements I made this diagram to try to understand how memory changes states, would you say it's accurate ? |
I don't think that is quite right. The viewcore tool provides a nested space usage report which is byte-accurate, which might be instructive:
HeapSys == all->heap TotalAlloc is all the bytes going from heap->in use spans->free to heap->in use spans->alloc. |
Sorry for hijacking nice thread and thanks for responses so far! Super useful. Question around heap alloc/inuse. I am correct that
In my test case I could see 300MB in |
It's more batch allocation than preallocation, but yes. You can also think about it as recently freed objects which live on the same page as a live object. Just from the stats I don't think there's an easy way to distinguish the two. It all depends on when the GC last finished. |
I am wondering, with Go 2 coming up, could it be considered to revamp the MemStruct structure ? If not could we consider having a new one ? |
@sylr please file a proposal for what you'd like to see in the revamp. We have decided that our experiment to allow questions on the issue tracker has not had the outcome we desired, so I am closing this issue. I'm sorry that we can't answer your question here. There are many other methods to get help if you're still looking for answers:
Thanks |
Hi,
I don't understand what the value of
MemStats.HeapReleased
represents.From what I read from the doc it's the amount of memory that has been released to the system (if you stop here you should assume that this value is a counter always growing) ... and has not yet been reacquired for the heap (things start to be weird here).
So if I'm not mistaken this value is impacted by two things:
I don't understand why this has not been split into 2 values, e.g. :
MemStats.HeapReleased
: Total cumulative Idle memory returned to the system.MemStats.HeapReacquired
: Total cumulative Idle memory reacquired for the heap.I think this would make easier to understand what happen to the idle memory.
Regards.
The text was updated successfully, but these errors were encountered: