为了提高垃圾回收的性能,java在parallel回收的时候可以设置同时并行处理的线程数也就是ParallelGCThreads,如果你没有设置该参数,该参数jvm会默认设置成online的cpu的核数但并不包括被shutdown的cpu的核数。
Linux 下获取online的cpu的核数
int online_cpus = ::sysconf(_SC_NPROCESSORS_ONLN);
前面曾经提到过GC的主要过程是由VMThread线程执行,在执行parallel的时候,VMThread线程实际上是在等待线程执行结果的,这也就是为什么并没有设置ParallelGCThreads= online cpu core-1
Parallel gc 和CMS里的young区都可以设置ParallelGCThreads参数,下面主要讲的是Parallel GC
Parallel Threads本质是由gcTaskManager管理的gcTaskThread, 在parallelScavenge.cpp 中的initialize() 方法中通过GCTaskManager::create(ParallelGCThreads);初始化gcTaskThread的,也就是当jvm启动的时候thread 就已经创建并且运行。
参数:BindGCTaskThreadsToCPUs
jvm在linux中并没有对gcTaskThread线程绑定到固定的cpu上,但在solaris上却支持了,请参考函数os::distribute_processes 和 os::bind_to_processor
这是一个存放的元素是GCTask的链表结构,指针_insert_end指向最后一个元素,指针_remove_end指向第一个元素
GCTask本身也是一个链表结构,指针_newer指向后面的元素,_older指向前面一个元素,可以参考下面的图
当增加一个GCTask C的时候,会从Queue中取出_insert_end的GCTask B,设置B _newer 为C, 设置C older_为B,设置_insert_end为C
当取一个GCTask的时候,从Queue取出_remove_end的GCTask B, 设置_remove_end为C,设置C的old为null, 设置 B的new为nul
参数 UseGCTaskAffinity
通过设置_affinity 属性用于表示该task的是由哪个线程执行,当GCTaskThread运行的时候会取出该线程的所对应的task
做法使用轮询从queue的第一个开始顺序查找,一直找到然后移除。
GCTaskThread不停轮询GCTaskQueue,当Queue里面没有数据的时候,线程会wait等待,直到有数据插入notify线程,由于Queue的操作并不是线程安全的,需要在增加和删除的时候申请互斥锁MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag);
VMthread 线程在Parallel GC 时候将任务添加到queue中,然后等待结果。