There are a lot of strings that are duplicates of one another in the AM. This comes from all of the PB events the come across the wire and also tasks heart-beating in through the umbilical. There are even several duplicates from Configuration. By "interning" all of these strings on the Heap I have been able to reduce the resting memory usage of the AM to be about 5KB per task attempt. With about half of this coming from counters. This results in a 5MB heap for a typical 1000 task job, or a 500MB heap for a 100,000 task attempt job. I think I could cut the size of the counters in half by completely rewriting how counters work in the AM and History Server, but I don't think it is worth it at this point.
I am still investigating what the memory usage of the AM is like when running very large jobs, and I will probably have a follow-up JIRA for reducing that memory usage as well.