场景:
负责的算法平台项目将上传的算法jar包打包成一个spingboot的可执行jar包,项目中用命令启动该服务,命令如下:
String filePath = this.moduleFileRootPath + "/" + moduleId + "/" + version + "/algrithm-module-"
+ moduleId + "-" + version + ".jar";
nohup java -jar " + filePath + " --server.port=" + port + " --putParamsJson="
+ moduleConfigsJson
发现当120G内存的服务器启动20个左右的服务的时候,就不能在启动服务了,这远远低于我们的预期,我用jstat -gcutil 进程号 命令,结果如下:
S0、S1 代表两个Survivor区;
E 代表 Eden 区;
O(Old)代表老年代;
M(MateSpace)代表元空间(jdk1.8之后修改为mateSpace,之前是永久代Permanent);
CCS (Young GC)代表 类指针压缩空间使用率,下面会介绍类指针压缩;
YGC(Young GC)代表Minor GC;
YGCT代表Minor GC耗时;
FGC(Full GC)代表Full GC耗时;
GCT代表Minor & Full GC共计耗时。
当我看到元空间和类指针压缩空间使用率都百分之90多,我错误了将问题的方向指向这里,我以为是占用率过多导致的,但是FGC的次数是2,FGC时间也不是很频繁,看了博客说元空间内存的释放是要触发FGC的,所以问题并不在这。。。
然后执行jmap命令查看生产服务的堆的信息, jmap -heap 进程号,不看不知道一看吓一跳,最大堆竟然32g
突然想到,我们生成的算法服务没有指定jvm的参数信息,都是按照默认的生成的,去oracle官网找了一下官方文档,翻译成中文的意思如下:
符合预期,生成的服务的最大堆果然是官网上说的32g,这也就难怪服务器只能生成20个左右的服务了,所以把代码的修改为
"nohup java -Xms1024m -Xmx1024m -jar " + filePath + " --server.port=" + port + " --putParamsJson="
+ moduleConfigsJson
指定一下jvm合适的默认参数就行了
**
类指针压缩
**
什么是java对象的指针压缩?
1.jdk1.6 update14开始,在64bit操作系统中,JVM支持指针压缩
2.jvm配置参数:UseCompressedOops,compressed–压缩、oop–对象指针
3.启用指针压缩:-XX:+UseCompressedOops,禁止指针压缩:-XX:-UseCompressedOops
为什么要进行指针压缩?
1.在64位平台的HotSpot中使用32位指针,内存使用会多出1.5倍左右,使用较大指针在主内存和缓存之间移动数据,占用较大宽带,同时GC也会承受较大压力
2.为了减少64位平台下内存的消耗,启用指针压缩功能
3.在jvm中,32位地址表示4G个对象的指针,在4G-32G堆内存范围内,可以通过编码、解码方式进行优化,使得jvm可以支持更大的内存配置
4.堆内存小于4G时,不需要启用指针压缩,jvm会直接去除高32位地址,即使用低虚拟地址空间
5.堆内存大于32G时,压缩指针会失效,会强制使用64位(即8字节)来对java对象寻址,这就会出现1的问题,所以堆内存不要大于32G为好
指针压缩的原理是什么?
1.解释器解释字节码,植入压缩指令,进行编码、解码
2.需要操作系统底层支持:GC堆从虚拟地址0开始分配
哪些信息会被压缩?
1.对象的全局静态变量(即类属性)
2.对象头信息:64位平台下,原生对象头大小为16字节,压缩后为12字节
3.对象的引用类型:64位平台下,引用类型本身大小为8字节,压缩后为4字节
4.对象数组类型:64位平台下,数组类型本身大小为24字节,压缩后16字节
哪些信息不会被压缩?
1.指向非Heap的对象指针
2.局部变量、传参、返回值、NULL指针