一些看过Java8以后的垃圾回收日志的一般会对这么一句话感到很困惑:
Metaspace used 2425K, capacity 4498K, committed 4864K, reserved 1056768K
class space used 262K, capacity 386K, committed 512K, reserved 1048576K
第一个问题是,按照一般的理解,metaspace
似乎是一个整体,怎么还分成了四个部分?
第二个问题是,怎么metaspace
之后,还有一个class space
?两者之间的关系是怎样的?
先来看一幅图:
首先可以看到的是,这些used
,capacity
,committed
和reserved
并不纯粹是JVM的概念,它和操作系统相关。
先来看committed
和reserved
。reserved
是指,操作系统已经为该进程“保留”的。所谓的保留,更加接近一种记账的概念,就是操作系统承诺说一大块连续的内存已经是你这个进程的了。注意的是,这里强调的是连续的内存,并且强调的是一种名义归属。那么实际上这一大块内存有没有真实对应的物理内存呢?答案是不知道。
那么什么时候才知道呢?等进程committed
的时候。当进程真的要用这个连续地址空间的时候,操作系统才会分配真正的内存。所以,这也就是意味着,这个过程会失败。
举个例子来说,就好比张三找李四借钱,张三说借1000,李四在本子上记录了一笔说可以,借给你了,但是暂时不能给你,等你要用的时候再来领。于是过了一天,张三来领了300,这300就是committed
的,之前那1000就是reserved
的。很显然,如果李四给太多人都记了一笔,说不定等张三去借的时候,就没有了。
因此,这个reserved
更加接近记账的概念。
used
和capacity
就是JVM的概念了。这两个概念非常接近JVM一些集合框架的概念。一些Java集合框架,比如某种List的实现,会有size
和capacity
的概念。比如说ArrayList
的实现里面就有capacity
和size
的概念。假如说我创建了一个可以存放30个元素的ArrayList
,但是我实际上只放了20个元素,那么capacity
就是30,而size
就是20.这里的size
和used
就是一个概念。那么“元素”则是一个个内存块"block“。
capacity
和committed
的关系也可以此类比,只不过capacity
反而对应到used
,committed
对应到capacity
,而所谓的”元素“,就是chunk
。
至于class space
,要记住的是,metaspace
并不是全部用来放类对象的。比如说,因为每一个ClassLoader
都被分配了一块内存,这块内存可能并没有被用完,于是就会有一些内存碎片;metaspace
还需要放所谓静态变量。所以,class space
是指实际上被用于放class
的那块内存的和。