JVM问题情景分析

发布时间:2019-11-19 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了JVM问题情景分析脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。

问题分析之死锁

@H_304_5@产生死锁必须同时满足以下四个条件:

  • 互斥条件:一段时间内某资只能被一个线程(进程)占有,若有其他请求线程只能等待。

  • 不剥夺条件:一个线程占用某资源后只能该线程自己释放资源,不能被其他线程夺走。

  • 请求和保持条件:一个线程去申请另外一个资源的时候,继续占有已分配的资源。

  • 循环等待条件:存在一个处于等待状态的线程集合{p1,...,pi,..},pi等待的资源被p(i+1)占有。

简单点说,对于两个线程A,B而言,先有线程A占有锁X,线程B占有锁Y,然后A继续申请锁Y,B继续申请锁X,但由于此时锁Y已经被B占有,A只能等待B释放锁Y,同理B也在等待A释放锁X。此时形成了一个线程分别等待对方释放锁的状况,即产生了死锁。

public class DeadLock {     PRivate static Lock lockA = new ReentrantLock();     private static Lock lockB = new ReentrantLock();          /*private static Object monITor1 = new Object();     private static Object monitor2 = new Object();*/      public static void main(String[] args)  {                  try {             Thread.sleep(5000);         } catch (InterruptedException e) {             e.printStackTrace();         }                  new ThreadA().start();         new ThreadB().start();              }          static class ThreadA extends Thread{                  @override         public void run() {             lockA.lock();             try {                 Thread.sleep(2000);                                  lockB.lock();                 System.out.println("in lockB");                 lockB.unlock();                              } catch (Exception e) {                 // TODO: handle exception             }finally{                 lockA.unlock();             }                      /*    synchronized (monitor1) {                              try {                     Thread.sleep(2000);                 } catch (InterruptedException e) {                     e.printStackTrace();                 }                                  synchronized (monitor2) {                     System.out.println("in monitor2");                 }                                               }*/                      }                       }               static class ThreadB extends Thread{                  @Override         public void run() {             lockB.lock();                          try{                                  Thread.sleep(4000);                                  lockA.lock();                 System.out.println("in lockA");                 lockA.unlock();                              }catch(Exception e){                 e.printStackTrace();             }finally{                 lockB.unlock();             }                      /*    synchronized (monitor2) {                 try {                     Thread.sleep(4000);                 } catch (InterruptedException e) {                     e.printStackTrace();                 }                                  synchronized(monitor1){                     System.out.println("in monitor2");                 }             }             */                      }              } } 

上面代码是一个简单的例子,产生死锁一般可以用jstack命令生成线程快照来分析,当然更好用的有jdk自带VisualVM图形化工具。在java_home目录下的bin文件夹里面,可以找到jvisuaLVM。在linux下可以使用命令行:

cd $JAVA_HOME/bin
./jvisualvm&

当然JAVA_HOME一般都export到PATH下了,可以直接命令行输入

jvisualvm&

在visualVM中进入对应的进程,可以看到visualVM直接帮助我们检测到了死锁:

JVM问题情景分析


点击线程dump按钮,查看dump堆文件:

JVM问题情景分析


由于这里的死锁程序使用的Lock锁,可以看到两个线程Thread-0,Thread-1的状态为WAITING(如果使用上面程序注释掉的synchronized锁,线程状态为阻塞)。Thread-1已拥有锁的id为<...71bc8>,等待锁id为<...73008>,相反Thread-0拥有锁<...73008>,正在等待锁<...71bc8>。

问题分析之内存泄露/内存溢出

1. 堆内存溢出(outOfMemoryError:java heap space)

内存泄露memory leak:指的是申请内存后无法释放该内存。在java当中指的是存在无用,而且是可达的(导致jvm无法回收)的对象。
内存溢出out of memory:指的是申请内存时,已没有足够的内存空间供使用。
内存泄露如果大量的堆积,消耗足够多的内存,最后会产生内存溢出。

下面是一个内存泄露最终导致内存溢出的例子:

public class MemoryLeak {     public static void main(String[] args) {         sleep(9000);         Vector v = new Vector();         long count = 0;         while (true) {             Object o = new Object();             v.add(o);             o = null;             count++;             if (count % 100 == 0) {                 System.out.println("vector Size: " + v.size());                 long freeMem = Runtime.getRuntime().freeMemory()                         / (1024 * 1024);                 System.out.println("freeMemory is " + freeMem + "M in count->"                         + count);             }         }     }      private static void sleep(long millis) {         try {             Thread.sleep(millis);         } catch (InterruptedException e) {             e.printStackTrace();         }     } } 

我们加上jvm启动参数,将最小和最大堆大小均设为20M:

-XMs20m -Xmx20m

最后得到溢出异常:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:3210)
at java.util.Arrays.copyOf(Arrays.java:3181)
at java.util.Vector.grow(Vector.java:266)
at java.util.Vector.ensureCapacityHelPEr(Vector.java:246)
at java.util.Vector.add(Vector.java:782)
at com.ethfoo.jvm.MemoryLeak.main(MemoryLeak.java:17)

JVM问题情景分析

代码当中我们不停的往Vector里面加Object对象,并且每个对象的引用O置为null。我们假设这些Object已是无用对象,虽然我们将o置为null,但其实Vector里面仍然保存每个Object对象的引用,所以Object对jvm来说是可达的,jvm无法对其进行回收。

2. 方法区内存溢出(outOfMemoryError:permgem space)

在jvm规范中,方法区主要存放的是类信息、常量、静态变量等。
所以如果程序加载的类过多,或者使用反射、gclib等这种动态代理生成类的技,就可能导致该区发生内存溢出,一般该区发生内存溢出时的错误信息为:

outOfMemoryError:permgem space

可以使用jvm参数调整方法区的大小分配:

-XX:PermSize -XX:MaxpermSize

3. 线程栈溢出(StackOverflowError)

一般线程栈溢出是由于递归太深或方法调用层级过多导致的。
可以使用以下参数来调整栈大小的分配,线程栈越大递归调用的深度越大,但同时由于总的内存大小限制,会使总体能够启动的线程数目减小。

-Xss

4. 直接内存溢出(OutOfMemoryError: Direct buffer memory)

试运行以下代码,直接分配大量堆外内存:

public static void main(String args[]){     for(int i=0; i<3024; i++){             ByteBuffer.allocateDirect(1024*1024*1024);             System.out.println(i);             //System.gc();     } }

最后导致结果:

Exception in thread "main" java.lang.OutOfMemoryError: Direct buffer memory
at java.nio.Bits.reserveMemory(Bits.java:658)
at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:123)
at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:311)
at com.ethfoo.jvm.OutOfMemory.directMemeory(OutOfMemory.java:28)
at com.ethfoo.jvm.OutOfMemory.main(OutOfMemory.java:10)

需要注意的是,直接内存是无法触发jvm的内存回收机制的,直接内存可以被垃圾收集器回收,但是只能是由堆中内存触发gc,同时顺便对直接内存进行垃圾收集清理。

脚本宝典总结

以上是脚本宝典为你收集整理的JVM问题情景分析全部内容,希望文章能够帮你解决JVM问题情景分析所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。