1.zgc的堆大小= Reserved内存+Free内存+User内存的大小,Reserved保留内存的是为了在并发转移阶段的过程中,并发gc线程发现内存不足的时候才使用的,一般的内存请求时不会使用到保留内存的,保留内存的大小=并行工作线程的数量(注意是并行gc工作线程的数量不是并发gc工作线程的数量) * 小页面的内存大小(一般是2M) + 一个中页面的内存大小(一般是32M),比如如果并行gc工作线程数量是10个,那么保留内存的大小就是10 * 2M + 32M = 42M
2.zgc日志中的Gc Locker Stall 是由于本地代码的执行产生的,由于在jni本地方法中可以通过jni_GetStringCritical等直接访问本地内存的数据,前提是必须使用 GC Locker进行加锁以保证安全,在加锁执行本地代码期间,如果发生zgc请求,那么此时zgc会被延迟,直到Gc Locker释放锁,日志中这里的等待时间就是zgc等待Gc Locker锁释放的时间.
3.并发标识阶段每个线程(应用线程+gc线程)都会标记对象,每个线程都有自己的标记带(待标记的对象列表),当Gc线程标记完自己标记带的所有对象后,会通过主动或者被动的方式把应用线程的标记带的对象刷新到全局标记带中,然后由Gc线程一起标记,由于在这个过程中应用线程在不停的标记对象,所以为了有一个结束的过程,所以引用了重新标记阶段,目的是为了标记完应用线程中所有的标记带,–附标记条带的最大大小由参数ZMarkStackMax=8G指定,如果标记过程中使用的标记栈空间大于该值,那么jvm会直接退出
4.zgc的地址多视图映射依赖于Mmap映射函数,zgc目前可以基于共享内存或者共享文件的方式映射到多个地址视图中(Remapper,M0,M1),这个mmap映射会在jvm启动时映射完成.
5.每个类加载器加载的类都会放到一个ClassLoaderData的结构中,每个类都有一个类对象(InstanceKlass),也有多个类实例(InstanceOop),我们代码里面加锁Synchronized(ClassA.class)的形式其实锁的就是类对象(InstanceKlass),这个类对象对于每个类加载器来说只有一个,所以可以起到互斥的作用,注意如果此时也有一个类实例(ClassA oobA = new ClassA()),然后也有Synchronized(oobA)的代码时,这一段代码和Synchronized(ClassA.class)锁住的这一段代码不是互斥的关系,因为他们锁的并不是同一个对象.