jvm runtime contant pool String 占用测试

最近公司测试环境Cassandra的一次PermGen Space,好久没排查此类问题了,对JVM也有点陌生,借此机会重新学习学习,经过一段时间的不断尝试,终于基本定位问题所在,PermGen OOM 是因为Casandra 在运行过程中不断的往PermGen里面放入String常量导致OOM,但没找到Cassandra在什么情况下会不断的产生新的String 常量,还要继续跟进。

排查过程如下: 

 

       好久没真正排查OOM问题了,一开始也没什么办法,只好重新启动Cassandra ,过一段时间又继续OOM,一直感觉很诡异,之前运行那么久都没有问题,怎么现在老是OOM,查看OOM日志,也没什么明确信息,然后拿着OOM时的java_pidXXX.hprof文件,通过Eclipse 的MemoryAanlyzerTool工具分析,看了半天,也没看出来什么明显问题,后来无意中发现jmap这个命令(其实之前也用过,好久没用了都忘得差不多了,看来久不久得练练)可以直接查看当前heap使用情况,直接jmap -heap pid,发现我们Cassandra实例内存默认配置如下:

Heap Configuration:

   MinHeapFreeRatio = 40

   MaxHeapFreeRatio = 70

   MaxHeapSize      = 2147483648 (2048.0MB)

   NewSize          = 419430400 (400.0MB)

   MaxNewSize       = 419430400 (400.0MB)

   OldSize          = 5439488 (5.1875MB)

   NewRatio         = 2

   SurvivorRatio    = 8

   PermSize         = 21757952 (20.75MB)

   MaxPermSize      = 85983232 (82.0MB)

 

PernGen Size 的值使用JVM默认值,配置中没有具体指定,而我们的Cassandra OOM以后又启动起来,Perm Generation 已经使用了81M,接近100%的使用率,怪不得运行一段时间以后又继续OOM,只好手动设置Cassandra MaxPermSize=256M,重新启动,感觉这样也没查出具体问题,继续查看permstat,命令

jmap -permstat pid

发现218566 intern Strings occupying 66681200 bytes,终于确定问题所在,原来里面保存了65M的String常量

现在基本确定OOM的原因了,但还是没搞清楚Cassandra是如何在运行过程中把String常量放入PermGen,还需继续努力。

 

下面是测试String的不同使用方法对JVM内存的使用情况:

 

环境:

java version "1.6.0_51"

jvm: Java HotSpot(TM) 64-Bit Server VM (build 20.51-b01-457, mixed mode)

 

程序伪代码1:

i=0

if(i<100000)

      i++;

String.valueOf(i).intern()

 

结论:

1、String 对象会在新生代创建并占用内存

2、String 的值会被放入永久代中并占用内存

2、当新生代GC时,不会把String对象指向的String字符串转入老年代中,这些字符串已经被放入永久代,只会把String对象其他信息(具体还不能确定是什么信息)放入老年代

 

占用内存相对较少,但String字符串存放在永久代,下面是YGC=4的时候,JVM使用情况

S0C     S1C     S0U   S1U      EC         EU          OC            OU          PC       PU      YGC  YGCT  FGC  FGCT     GCT

2112.0 2112.0  9.8    0.0   17024.0   571.0    63872.0     7337.4   11264.0 11120.7      4    0.023   0      0.000    0.023

 

程序伪代码2:

i=0

if(i<100000)

      i++;

String.valueOf(i) 或者new String(i+"")或者 i+""

 

结论:

1、String 对象会在新生代创建并占用内存

2、String 的值不会被放入永久代中并占用内存

2、当新生代GC时,会把String对象指向的String字符串和String对象其他信息都放入老年代

 

new String(i+"") 占用内存相对较少,下面是YGC=4的时候,JVM使用情况

  S0C     S1C     S0U   S1U      EC         EU          OC            OU          PC       PU      YGC  YGCT  FGC  FGCT     GCT

2112.0 2112.0 2112.0  0.0   17024.0   5835.4   63872.0    28361.7   5120.0 4952.8      4    0.064   0      0.000    0.064

 

i+"“ 与 new String(i+"") 占用内存差不多,下面是YGC=4的时候,JVM使用情况

S0C     S1C     S0U   S1U      EC         EU          OC            OU          PC       PU      YGC  YGCT  FGC  FGCT     GCT

2112.0 2112.0 2112.0  0.0   17024.0   965.2    63872.0    28373.7   5120.0 4952.5      4    0.081   0      0.000    0.081

 

String.valueOf(i) 占用内存相对较多,下面是YGC=4的时候,JVM使用情况

 S0C     S1C     S0U   S1U      EC         EU          OC            OU          PC       PU      YGC  YGCT  FGC  FGCT     GCT

2112.0 2112.0 2112.0  0.0   17024.0   571.0    92956.0    55772.8   8252.0 4949.8      4    0.129  96      0.468    0.598

 

 

你可能感兴趣的:(jvm,cassandra)