对于堆内内存的监控

JVM提供了一些图形化的工具 JConsole VisualVM 可以直接连接到Java进程,在图形化中掌握内存的情况

JConsole为例,内存显示也分为了堆内存 堆外部分

jstat jmap等工具,提供了一些选项,可以查看堆 方法区等使用数据

使用jmap等提供命令,生成堆转储的文件

使用的是Tomcat,可以直接查看内存管理

这个问题,需要我们清晰的对JVM区域有个认知

以及对于特定区域,该使用上面工具去查看

对于收集工具,有JConsole 和 JMC

JMC可以配合JMX进行普通的管理

还可以配合JFR技术,以一种很低开销的,收集和分析JVM底层的Profiling 和 事件等信息

那么,我们先看下对内部的结构

图片

之前版本的GC的年代区分如上

1.新生代

新生代是对象创建和销毁的对象

里面分为Eden区和Survivor区域,在GC过程中,会进行区域的拷贝,同时整理内存

然后就是TLAB的概念,就是为每一个线程预先分配一个私有区域,避免线程保存变量的时候,需要请求分配,这可能导致出现锁机制,关于这个分配,是在Eden区域的

图片

分配流程如上,就是start end是固定的,top指向现在分配的地方了,每当分配一些,就移动top

top到头了,end就会在分配一块

老年代,就是存储长时间存活或者大对象的地方

永久代

存储Java类对象 常量池 Intern字符串缓存的地方

在Java 8之后,已经无了

对于常见的JVM参数有

-Xmx

设置最大堆体积

-XMS

设置最小堆空间

-XX:NewRatio=value

老年代和新生代的比例

默认比例是1:2

新生代占有堆空间的1/3

-XX:NewSize=value

直接设置内存大小

-XX:SurvivorRatio=value

Eden和Survivor的大小比例,默认是1/8 两个Survivor的区域相加和Eden就是 2:8

而且,JVM并不会直接将堆的大小扩展至Xmx的上限,而是等待内存有需求的时候,恢复到设置的上限

然后,我们看下JVM对外内存包含上面

对于JMC或者JConsole的管理界面,会统计非堆的内存,下面是JMC的截图

图片

这就统计了非堆内存的信息

然后我们开启NMT(堆外空间存储统计),进行打印统计内存

-XX:NativeMemoryTracking=summary

并且在应用退出的时候,打印NMT统计信息

-XX:+UnlockDiagnosticVMOptions -XX:+PrintNMTStatistics

图片

运行了一个HellpWorld,在程序结束的时候,打印了对应的NMT统计信息

第一部分是Java对

然后是Class的内存占用,元数据空间

可以利用下面的参数进行调整大小

-XX:MaxMetaspaceSize=value

然后就是可以调整类加载器元数据区大小

如下

-XX:InitialBootClassLoaderMetaspaceSize=30720

然后是线程,有足足25个

里面有Java线程 程序主线程 Cleaner线程 GC等本地线程

这是因为JDK9给出的默认GC是G1,对于高并发的场景有效,但是较为复杂

所以我们可以替换为单线程的GC

-XX:+UseParallelGC

下面是替换了默认GC,关闭了

进一步减少线程,就是可以关闭JVM的动态编译

JIT的TieredCompilation

使得本地线程变少

-XX:TieredCompilation

然后是CodeCache的相关内存

-XX:InitialCodeCacheSize=value

设置这部分的初始大小

-XX:ReservedCodeCacheSize=value

所以,减少线程和内存的开销,可以考虑替换对应的垃圾收集器

考虑关闭JIT

减少Direct Buffer的直接内使用

发表评论

邮箱地址不会被公开。 必填项已用*标注