I will only provide you an example against jdk-15 using JOL (that is the only reliable tool I would ever trust for this), for a ConcurrentHashMap with 10 entries, it is up to you from there.
Map<String, Integer> throttleMap = new ConcurrentHashMap<>();
for(int i = 0; i< 10; ++i){
    throttleMap.put((""+i).repeat(10), i);
}
System.out.println( GraphLayout.parseInstance((Object)throttleMap).toFootprint());
This will output:
 COUNT       AVG       SUM   DESCRIPTION
    10        32       320   [B
     1        80        80   [Ljava.util.concurrent.ConcurrentHashMap$Node;
    10        16       160   java.lang.Integer
    10        24       240   java.lang.String
     1        64        64   java.util.concurrent.ConcurrentHashMap
    10        32       320   java.util.concurrent.ConcurrentHashMap$Node
    42                1184   (total)
Understanding the above is not trivial. Integer is the easiest one:
- 12 bytes for two headers
- 4 bytes for the inner int field
So 16 bytes for one, you have 10 of those, thus that line:
0        16       160   java.lang.Integer
an instance of String is more involved:
- 12 bytes for headers
- 4 bytes for hashfield
- 1 byte for coderfield
- 1 boolean for hashIsZerofield (what is hashIsZero?)
- 2 bytes for padding
- 4 bytes for value(byte [])
So 24 bytes * 10:
 10        24       240   java.lang.String
That inner byte [] will also add:
- 12 bytes of headers (byte[]is an Object).
- 4 bytes for the lengthfield
- 10 bytes for each of the 10 bytes
- 6 bytes padding
Thus that:
 10        32       320   [B
Getting the overall picture is left as an exercise to you.