问题
Recently I was able to get an object's address using sun.misc.Unsafe class.
And now I am trying to find programmatically an actual generation where my object is located. For this I want to know the starting and ending points of each generation. If Java (Oracle JVM) provides any tools to resolve this issue? I believe not, since even different GCs require different memory structures (e.g. G1), and this makes the task even more interesting :)
What I want to know here is just a couple of numbers representing the borders of generations in memory, like this:
young gen: start point - 8501702198
end point - 9601256348
Would love to hear even your craziest ideas about a black magic that allows to determine where different generation areas are placed in memory.
回答1:
This is possible with HotSpot JVM though somehow complicated.
The key idea is to use VMStructs
- the information about HotSpot internal constants and types embedded right into JVM shared library.
For example, ParallelScavengeHeap::_young_gen
VM global variable contains the pointer to PSYoungGen
structure that has _virtual_space
member with the boundaries of Parallel collector's young generation. Similarly, GenCollectedHeap::_gch
global points to the structure describing CMS collector generations.
I've made a proof-of-concept project to demonstrate the usage of VMStructs. It is pure Java, no extra libraries required, but it deeply relies on the undocumented JDK internals and may not work on all Java versions. I've tested this on JDK 8u40 and JDK 7u80 on Windows and Linux.
- JVM.java - the code for reading VMStructs;
- HeapInfo.java - the sample program to get addresses of Heap generations.
回答2:
I don't know how to get exactly the borders of young and old generations (not even sure it's possible). In case of G1 it became even more complicated because it's allowed to have more than one old generation region due to unusual heap structure of G1.
But you can use tricky heuristic to determine whether object is in old generation or not without knowing borders of generations.
Let's use some black magic secret knowledge about hotspot internals: every object contains header with all necessary information about locking, identity hashcode, and most important, age.
Extracting age will look like this:
return unsafe.getByte(targetObject, 0L) & 0x78;
where 0x78 is corresponding mask in object header for its age (bits from 4th to 7th inclusive).
Obtain MaxTenuringThreshold
parameter via Management API:
MBeanServer server = ManagementFactory.getPlatformMBeanServer();
HotSpotDiagnosticMXBean bean = ManagementFactory.newPlatformMXBeanProxy(
server,
"com.sun.management:type=HotSpotDiagnostic",
HotSpotDiagnosticMXBean.class);
int threshold = Integer.valueOf(bean.getVMOption("MaxTenuringThreshold").getValue());
Now you know object's age and tenuring threshold of your application, so you can assume that if age is greater than threshold, it's in old generation.
WARNING: It's heuristic based on magic and secret knowledge.
- It will not work, if someone will synchronize on target object while you are reading it's age, because VM will move header to stack and replace header with pointer to stack
- It will not work with
XX:+UseAdaptiveSizePolicy
, so you should explicitly disable it. - Some object can be allocated straight in old generation (e.g. because of it's size)
- Type I error prone
- This approach is illegal, unsafe and might be incorrect and jvm dependent
来源:https://stackoverflow.com/questions/30599986/how-to-find-out-where-exact-young-old-gen-is-located-in-memory