前言:原来的文章不是md形式,写的也比较乱,现在看看 有点不好意思,就重新修正下。
今天群里分享这个图片,又这个图片引起了一系列讨论,我们队jvm的理解都是局限于知其然不知其所以然的阶段啊。
类似的问题:
metaspace在不在堆中?
directory memory和native memory关系?
讨论了一堆,记录下自己的理解,不一定正确。。。
metaspace在不在堆中? 不在。
可以参考这篇文章:深入探究 JVM | 探秘 Metaspace ---虽然年代写的比较久远,但作者的理解我感觉哈 是比较准的。
这个是jdk1.8的新特性,1.8以前呢,HotSpot JVM堆上有个永久代,存放类和方法的元数据以及常量池。1.8以后呢把永久代移除了,方法区移至 Metaspace,字符串常量移至 Java Heap。
为啥要这么干?
1 由于 PermGen 内存经常会溢出,引发恼人的 java.lang.OutOfMemoryError: PermGen,因此 JVM 的开发者希望这一块内存可以更灵活地被管理,不要再经常出现这样的 OOM。
我觉得这个原因比较实在,现在比较流行的框架都喜欢用反射,比如spring的aop,一般这种动态代理的类都会占用方法区的资源的。
2 移除 PermGen 可以促进 HotSpot JVM 与 JRockit VM 的融合,因为 JRockit 没有永久代。
一般情况下:设置Metaspace的参数-XX:MetaspaceSize -XX:MaxMetaspaceSize 这两个参数的值最好一致,值的大小可以根据监控情况动态的调整一下。 如果Metaspace由于空间不足引起动态扩容,会引发FULL GC。
其他两篇文章参考:
由「Metaspace容量不足触发CMS GC」从而引发的思考
JVM参数MetaspaceSize的误解
directory memory和native memory关系? 可以理解为directory memory是native memory的一部分。
可以参考这篇文章:
JVM的Heap Memory和Native Memory 这篇文章可以先熟悉下概念。
一次堆外OOM问题排查 这篇文章详细的说了下堆外内存OOM及回收方式 而且有样例,值得一看。
native memory中文叫本地内存,狭义的理解下,对jvm来说,就是不受jvm垃圾回收机制主动管理的内存就是本地内存。
directory memory指的是NIO direct buffer操作的本地内存。
需要注意的是DirectBuffer这个引用是分配在堆上,受gc控制的,而且记录分配了多少堆外内存的参数在java.nio.Bits类中,如下图:
我还读过一篇因为这个参数造成OOM,其实本地内存并没有超限,可惜当时没存。
还读了一篇JVM进程无缘无故的挂了,后来看linux日志是本地内存用的太多,被操作系统杀死了,可惜也没存。
他的回收机制叫Cleaner机制,Cleaner实现了PhantomReference,具体研究下代码吧,就是如果DirectBuffer被垃圾回收器回收的话,会通过通知机制回收directory memory。
一般给的建议是自己申请的堆外内存,不用的时候最好自己回收下。DirectBuffer接口有个cleaner()方法可以获得Cleaner ,调用Cleaner.clean方法就可以回收堆外内存。
2018-12-14补充
最新理解,full gc可以看看gc日志,如果发生full gc 就会回收对yung old permanent区都进行回收
2018-12-26补充 nio buffer用的是内核内存,主要目的是减少一次从内核态到用户态的内存拷贝。