JVM学习之路03--(JVM案例分析)

1.了解了监视工具以后就来分析一些小案例

   先来体验一下堆内存溢出的感觉。对内存默认是分很多的,很难溢出的,所以我们要设置一下起始堆内存分配的大小。设置最大堆内存为50M,初始堆内存为50M,垃圾回收器使用单线程垃圾回收器。

 

package com.wx.jvm;

import java.util.ArrayList;
import java.util.List;

public class TestMemory {
    public static void main(String[] args) {
        try {
            Thread.sleep(10000);
            fillHeap(100);
            Thread.sleep(10000);
        }catch (Exception e){
            e.printStackTrace();
        }

    }
    private static void fillHeap(int num) throws Exception{
        List<OOMObject> oomObjects=new ArrayList<OOMObject>();
        for (int i=0;i<num;i++){
            Thread.sleep(50);
            oomObjects.add(new OOMObject());
        }
        System.gc();
    }
    private static class OOMObject {
        //64k的大小
        public byte[] placeholder=new byte[64*1024*20];
    }
}

 运行:

 

2.测试一下线程,可以监控到死循环的线程和处于等待状态的线程

   

package com.wx.jvm;

import java.io.BufferedReader;
import java.io.InputStreamReader;

public class TestThread {
    /**线程死循环演示*/
    public static void createBusyThread(){
        Thread thread=new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("进入死循环的线程");
                while (true);
            }
        },"createBusyThread");
        thread.start();
    }
    /**线程锁等待*/
    public static void createLockThread(final Object lock) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("createLockThread");
                synchronized (lock) {
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

            }
        },"createLockThread");
        thread.start();
    }
    public static void main(String[] args) throws Exception{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        br.readLine();
        createBusyThread();
        br.readLine();
        Object object = new Object();
        createLockThread(object);
    }
}

启动死循环的线程:

进入处于等待状态的线程:

可以清楚的看到线程是在26行处处于等待状态

 

3.案例三:检测死锁

   这个代码常见了一百个线程,但是锁只有两把,当a=1时,线程拿到的是Integer的值为1的对象的锁,此时试图去拿Integer的值为2的对象的锁执行下一个步骤,但是如果另一个线程a=2,即他已经拿到Integer的值为2的对象的锁,那么就已经出现了死锁。

package com.wx.jvm;

public class TestDeadThread implements Runnable {
    int a, b;

    public TestDeadThread(int a, int b) {
        this.a = a;
        this.b = b;
    }

    @Override
    public void run() {
        synchronized (Integer.valueOf(a)) {
            synchronized (Integer.valueOf(b)) {
                System.out.println(a + b);
            }
        }
    }

    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            new Thread(new TestDeadThread(1, 2)).start();
            new Thread(new TestDeadThread(2, 1)).start();
        }
    }
}

启动:

ok,这已经检测到死锁了。这下可以把线程dump出来,得到一个非常详细的报告。

下面使用jconsole查看一下,他有专门检测死锁的:

 

4.案例四:当堆内存溢出的时候dump这个错误到指定的文件位置,以便后续的分析

   参数设置:-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=f:/dump

  

 

代码:

package com.wx.jvm;

import java.util.ArrayList;
import java.util.List;

public class HeapOOM {
    static class OOMObject{
        public String[] stringArray=new String[32*1024];
    }
    public static void main(String[] args) {
        List<OOMObject> list=new ArrayList<OOMObject>();
        while (true){
            list.add(new OOMObject());
        }
    }
}

运行:

用工具打开:

分析可疑内存溢出问题:

 

概况:

查看内部对象的树:

5.案例5:栈内存溢出演示,可以疯狂创建线程即可使栈内存溢出

 这个我就不试了,读者可以试试。

public class JavaVMStackOOM {
	private void dontStop() {
		while (true) {
		}
	}

	public void stackLeakByThread() {
		while (true) {
			Thread thread = new Thread(new Runnable() {
				@Override
				public void run() {
					dontStop();
				}
			});
			thread.start();
		}
	}

	public static void main(String[] args) throws Throwable {
		JavaVMStackOOM oom = new JavaVMStackOOM();
		oom.stackLeakByThread();
	}
}

6.案例6:找溢出,和上一个不一样这个是栈的深度太深,栈帧出不来。

package com.wx.jvm;

public class JavaVMStackSOF {
        private int stackLength = 1;
        public void stackLeak() {
            stackLength++;
            stackLeak();
        }
        public static void main(String[] args) throws Throwable {
            JavaVMStackSOF oom = new JavaVMStackSOF();
            try {
                oom.stackLeak();
            } catch (Throwable e) {
                System.out.println("stack length:" + oom.stackLength);
                throw e;
            }
        }
}

7.案例7:本机直接内存溢出

   什么是直接内存,就是JVM做本地调用的时候,用到JVM之外的内存。如果机器剩余的内存比较小了,JVM做本地方法调用就会可能会使本机直接内存溢出。

  参数设置:-Xmx20M -XX:MaxDirectMemorySize=10M

public class DirectMemoryOOM {
	private static final int _1MB = 1024 * 1024;

	public static void main(String[] args) throws Exception {
		Field unsafeField = Unsafe.class.getDeclaredFields()[0];
		unsafeField.setAccessible(true);
		Unsafe unsafe = (Unsafe) unsafeField.get(null);
		while (true) {
			unsafe.allocateMemory(_1MB);
		}
	}
}

 直接内存不归JVM管,也就是说GC不会回收这个内存,进一步说就是如果我们自己管好这部分的内存效率是非常高的。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

时空恋旅人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值