对于 java 虚拟机, 像我这样工作才两年的会是比较陌生和神秘, 但是时候, 需要对 JVM 有一定的认识, 并且能够设置一些参数. 下面是自己学习到的内容.
这里需要使用一个 java 自带的一个工具, VisualVM. 使用 IDEA 下载一个 VisualVM.
一, 查看程序的 JVM 内存
首先任务参数有不要设置, 然后编写一个程序.
- public class JavaHeapTest {
- public final static int OUTOFMEMORY = 200000000;
- private String oom;
- private int length;
- StringBuffer tempOOM = new StringBuffer();
- public JavaHeapTest(int leng) {
- this.length = leng;
- int i = 0;
- while (i < leng) {
- i++;
- try {
- tempOOM.append("a");
- } catch (OutOfMemoryError e) {
- e.printStackTrace();
- break;
- }
- }
- this.oom = tempOOM.toString();
- }
- public String getOom() {
- return oom;
- }
- public int getLength() {
- return length;
- }
- public static void main(String[] args) {
- JavaHeapTest javaHeapTest = new JavaHeapTest(OUTOFMEMORY);
- System.out.println(javaHeapTest.getOom().length());
- }
- }
然后使用 VIsualVM 运行程序.
程序运行起来, 但是第一次需要设置 VisualVM 的位置
程序运行起来后后堆的情况.
上面的图是没有设置任何程序的事情下做的, 为什么需要看堆的大小, 因为堆存放对象的实例, 一般都会需要设置该值, 在没有做任何设置的时候, 就会看到堆的内存可能达到 1G 的大小. 有时候需要模拟线上环境的上的 Java 内存大小, 在 IDEA 中设置下一年堆的大小, 这里设置堆的初始化和最大值都一样, 以避免每次垃圾回收完成后 JVM 重新分配内存
设置之后运行程序, 堆的内存变为设置的大小, 但是这个时候有可能出现异常, 在我的电脑上就出现 java.lang.OutOfMemoryError: Java heap space, 该异常就是设置的堆内存太小导致, 但是一般情况下不会出现该情况, 因为上面的程序并不需要特别大的程序, 可能是我的笔记本电脑的原因.
上面知道看堆的大小, 接下来可以看一下堆中存储了什么. 在程序运行的时候, 需要快速点击堆 dump, 然后就看到如下
双击某个列表之后查看其中的内容, 而存储最多的就是程序中设置的 tempOOM 参数, 此时知道了堆中存储最大的内容是什么, 如果是其他程序, 某一个字段占用特多的内存, 可能就是程序出现问题了, 那么就需要对那个字段进行优化.
二, 查看程序的线程情况
接下来运行下面的程序:
- public class DeadLock {
- public static void main(String[] args) {
- Resource r1 = new Resource();
- Resource r0 = new Resource();
- Thread myTh1 = new LockThread1(r1, r0);
- Thread myTh0 = new LockThread0(r1, r0);
- myTh1.setName("DeadLock-1");
- myTh0.setName("DeadLock-0");
- myTh1.start();
- myTh0.start();
- }
- }
- class Resource {
- private int i;
- public int getI() {
- return i;
- }
- public void setI(int i) {
- this.i = i;
- }
- }
- class LockThread1 extends Thread {
- private Resource r1, r2;
- public LockThread1(Resource r1, Resource r2) {
- this.r1 = r1;
- this.r2 = r2;
- }
- @Override
- public void run() {
- int j = 0;
- while (true) {
- synchronized (r1) {
- System.out.println("The first thread got r1's lock " + j);
- synchronized (r2) {
- System.out.println("The first thread got r2's lock " + j);
- }
- }
- j++;
- }
- }
- }
- class LockThread0 extends Thread {
- private Resource r1, r2;
- public LockThread0(Resource r1, Resource r2) {
- this.r1 = r1;
- this.r2 = r2;
- }
- @Override
- public void run() {
- int j = 0;
- while (true) {
- synchronized (r2) {
- System.out.println("The second thread got r2's lock " + j);
- synchronized (r1) {
- System.out.println("The second thread got r1's lock" + j);
- }
- }
- j++;
- }
- }
- }
程序运行之后, 查看线程标签后直接告警出现了死锁的线程.
上面的程序可以看到蓝色部分为线程正常运行, 黄色为等待.
三, 使用 VisualGC 来查看年轻代, 老年代的堆内存的 GC 情况, 如果是频繁的 GC, 那么可能就是内存不足, 就需要增加堆内存.
上面的图大部分的 GC 都是在 Eden 区, 即对象都是朝生暮死的, 并且发生了 GC time 收集到 0 条 GC, 那么就是该程序一直运行可以 (这里程序运行时间很短, 在长时间观察, 可以得到更多的信息, 如果是将堆内存设置很小的时候, 那么就会经常发生 GC 的情况)
JVM 调优, 需要变设置参数, 边进行观察, 这样更容易理解其中缘由, 可以上手试一试.
来源: https://www.cnblogs.com/skyice/p/VisualVm.html