3.JVM重要知识点

一.三种JVM

二.堆(重点)

  • 一个JVM只有一个堆内存,堆内存大小是可以调节的

1.新生区

目的:控制对象的诞生,成长和死亡

分为:

  • 伊甸园区:所有对象都在伊甸园区new出来

  • 幸存0区和幸存1区:轻GC之后存下来的

2.老年区(养老区)

永久存在的对象放在老年区

步骤:

  • 伊甸园区满了之后进行轻GC幸存下来的放到幸存0区或幸存1区

  • 当伊甸园区、幸存0区和幸存1区都满了进行重GC,幸存下来的放到养老区???

  • 当伊甸园区、幸存0区、幸存1区和养老区都满了,会出现OOM

3.永久区

注意:

  • 元空间是逻辑上存在而物理上不存在的,又称为非堆,但是实际上是和堆放在同一个物理空间中

  • 方法区中的一小块为常量区

案例程序:

  • 默认情况下,JVM使用的最大内存为电脑总内存的四分之一,JVM使用的总内存为电脑总内存的十六分之一

  • 配置VM的参数: -Xms1024m -Xmx1024m -XX:+PrintGCDetails

@Test
public void test1() {
    //返回JVM试图使用的最大内存:默认情况下为电脑总内存的1/4
    long max = Runtime.getRuntime().maxMemory();
    //返回JVM的初始化总内存:默认情况下为电脑总内存的1/16
    long total = Runtime.getRuntime().totalMemory();

    System.out.println("max:" + max / (double) (1024 * 1024) + "MB");
    System.out.println("total:" + total / (double) (1024 * 1024) + "MB");

    //配置VM的参数: -Xms1024m -Xmx1024m -XX:+PrintGCDetails
}

 案例二:OOM

  • 配置VM的参数: -Xms8m -Xmx8m -XX:+PrintGCDetails

public class JVMTest {

    public static void main(String[] args) {
        //配置VM的参数: -Xms8m -Xmx8m -XX:+PrintGCDetails
        String s = "aaaaaaaaaa";
        while(true){
            s += s + new Random().nextInt(999999999) + new Random().nextInt(888888888);
        }
    }
}

 三.堆内存调优

  • 使用工具JProfiler

  • 内存快照分析工具:MAT(eclipse中使用),JProfiler

  • 作用:用于分析Dump文件,查找错误原因

使用步骤:

  • IDEA中在插件库中下载插件JProfiler

  • 在网上下载JProfiler桌面工具破解并安装

  • 在IDEA中配置JProfiler

 

 编写会OOM的代码,并配置VM options

编写程序

  • -Xms:设置初始化内存分配大小
  • -Xmx:设置最大分配内存
  • -XX:+PrintGCDetails:打印GC垃圾回收信息
  • -XX:+HeapDumpOnOutOfMemoryError:栈溢出信息生成Dump文件
//-Xms1m -Xmx8m -XX:+HeapDumpOnOutOfMemoryError
public class Demo01 {

    byte[] array = new byte[1*1024*1024];   //1M
    public static void main(String[] args) {
        ArrayList<Demo01> list = new ArrayList<>();

        int count = 0;

        while(true){
            list.add(new Demo01());
            count++;
        }
    }
}

生成的dump文件在项目的目录下的xxx.hprof,双击打开

使用工具排错

 四.GC

  • Eden与Survivor的内存大小比例为8:1:1

1.引用计数法:

  • GC的时候会将计数器为0的对象C给销毁。

2.复制算法

  • 幸存区from和幸存区to中谁是空的谁就是to,我们会将to中数据复制到from中保持to中数据为空

  • from和to区实际上为逻辑上的概念,保证to区一直空

  • 默认对象经过15次GC后还没有被销毁就会进入养老区

流程:

  • 将Eden区进行GC存活对象放入空的To区,将From区存活的放到空的To区

  • 此时From区为空变成了To区,To区有数据变为From区

  • 经过15次GC后From区还存活的对象会被移动到养老区

好处:没有内存碎片

坏处:浪费了内存空间(To区为空)

复制算法最佳使用场景:对象存活度较低(如果存活度较高,则From区空间全部被占满导致会将全部内容复制到To区)

3.标记清除算法

  • 需要两次扫描,第一次扫描标记存活对象,第二次扫描清除没有被标记的对象

优点:不需要额外的空间

缺点:两次扫描严重浪费时间,并且还会产生内存碎片

4.标记压缩算法

  • 在标记清除算法上进行优化,再扫描一次将存活对象移动到一起

总结:

五.JMM

  • Java Memory Model:java内存模型

 

posted @ 2020-03-14 23:43  All_just_for_fun  阅读(170)  评论(0编辑  收藏  举报