美文网首页
第二十七章、如何监控和诊断JVM堆内和堆外内存使用

第二十七章、如何监控和诊断JVM堆内和堆外内存使用

作者: 小母牛不生产奶 | 来源:发表于2018-11-15 21:16 被阅读102次

    了解JVM欸村的方法有很多,具体能力范围也有区别,简单总结如下:

    1、使用综合性的图形化工具,如JConsole、VisualVM(从Oracle JDK9开始,VisualVM已经不再包含在JDK安装包中)等。这些工具具体使用起来相对比较直观,直接连接到Java进程,然后就可以在图形化界面里掌握内存使用情况。

    以JConsole为例,其内存页面可以显示常见的堆内存和各种堆外部分使用状态

    2、也可以使用命令行工具进行运行时查询,如jstat和jmap等工具都提供了一些选项,可以查看堆、方法区等使用数据。

    3、也可以使用jmap等提供的命令,生成堆转储(Heap Dump)文件,然后利用jhat或Eclipse MAT等堆转储分析工具进行详细分析。


    堆内部是什么结构?

    对于堆内存,按照通常的GC年代方式划分,java堆内分为:

    1、新生代

        新生代是大部分对象创建和销毁的区域,在通常的java应用中,绝大部分对象生命周期都是很短暂的。其内部又分为Eden区域,作为对象初始分配的区域;两个Survivor,有时候也叫from、to区域,被用来放置从Minor GC中保留下来的对象。

    堆结构示意图

        JVM会随意选取一个Survivor区域作为“to”,然后会在GC过程中进行区域间拷贝,也就是将Eden中存活下来的对象和from区域的对象,拷贝到这个“to”区域。这种设计主要是未了防止内存的碎片化,并进一步清理无用对象;

        从内存模型而不是垃圾收集的角度,对Eden区域继续进行划分,Hotspot JVM还有一个概念叫做Thread Local Allocation Buffer(TLAB),据我所知所有OpenJDK衍生出来的JVM都提供了TLAB的设计。这是JVM为每个线程分配的一个私有缓存区域,否则,多线程同时分配内存时,为避免操作同一地址,可能需要使用加锁等机制,进而影响分配速度;从上图中可以看出,TLAB仍然在堆上,它是分配在Eden区域内的。其内部结构比较直观易懂,start、end就是起始地址,top(指针)则表示已经分配到哪里了。所以我们分配新对象,JVM就会移动top,当top和end相遇时,即表示该缓存已满,JVM会试图再从Eden里分配一块儿。

    2、老年代

        放置长生命周期的对象,通常都是从Survivor区域拷贝过来的对象,当然也有特殊情况,我们知道普通的对象会被分配再TLAB上;如果对象较大,JVM会试图直接分配再Eden其他位置上;如果对象太大,完全无法再新生代找到足够长的连续空闲空间,JVM就会直接分配到老年代。

    3、永久代

        这部分就是早期Hotspot JVM的方法区实现方式了,存储Java类元数据、常量池、Intern字符串缓存,再JDK8之后就不存在永久代这块儿了。


    如何利用JVM参数,直接影响堆和内部区域的大小?

    最大堆体积

    -Xmx value

    初始的最小堆体积

    -Xms value

    老年代和新生代的比例

    -XX:NewRatio=value

    默认情况下,这个数值是2,意味着老年代是新生代的2倍大;换句话说,新生代是堆大小的1/3;

    当然,也可以不用比例的方式调整新生代的大小,直接指定下面的参数,设定具体的内存大小数值:

    -XX:NewSize=value

    Eden和Survivor的大小是按照比例设置的,如果SurvivorRatio是8,那么Survivor区域就是Eden的1/8大小,也就是新生代的1/10,因为YoungGen=Eden+2*Survivor,JVM参数格式是:

    -XX:SurvivorRatio=value

    相关文章

      网友评论

          本文标题:第二十七章、如何监控和诊断JVM堆内和堆外内存使用

          本文链接:https://www.haomeiwen.com/subject/fceufqtx.html