zoukankan      html  css  js  c++  java
  • JVM 探究 (下)

    GC 详解:

      口诀:关于垃圾回收:分代收集算法 ——不同的区域使用不同的算法

      Young代:GC频繁区域

      Old代:GC次数较少

      Perm代:不会产生GC

      一个对象的历程!

    JVM在进行GC时,并非每次都是对三个区域进行扫描,大部分时候都是指的新生代!

      两个类型:

        普通GC:只针对新生代 -- GC

        全局GC:主要是针对老年代,偶尔伴随新生代 -- Full GC

    GC算法

    1. 复制算法
    2. 标记清除
    3. 标记整理
    4. GC引用计数 (了解,基本不用)

      GC引用计数(了解)

      闲谈:GC可达性算法

      复制算法

        年轻代中使用的就是复制算法

      优点:没有标记和清除的过程,效率高,没有内存碎片

      缺点:需要浪费双倍的内存空间

      Eden区,对象存活率极低,据官方统计,99%的对象在使用一次后,引用失效,推荐使用复制算法

      标记清除算法

        老年代一般使用这个,但是会和标记整理算法一起使用

      优点:不需要额外空间

      缺点:两次扫描耗时,会产生内存碎片,不连续

      标记清除整理算法

        减少了标记清楚算法的缺点:没有内存碎片,但耗时较为严重

      那什么时候考虑使用这个算法?

        在我们这个要使用的算法的空间中,假设这个空间中很少,不经常发生GC,那么可以考虑使用这个算法!

    GC算法总结

      内存效率:复制算法 > 标记清楚算法 > 标记清楚整理算法 (时间复杂度)

      内存整齐度:复制算法 = 标记清除整理算法 > 标记清除算法(内存碎片)

      内存利用率:标记清除整理算法 = 标记清除算法 > 复制算法

    从效率来说,复制算法最好,但是空间浪费较多!为了兼顾所有指标,标记清除整理会平滑一点,但是效率不尽人意!

    难道就没有一种最优的算法吗?

      答案:没有!分代收集算法:不同的区域使用不同的算法!没有最好的,只有最适合的。

    JVM参数

      JVM三种参数类型:

        标配参数、X参数(参数)、XX参数;

      标配参数:

    • -version
    • -help
    • -showversion

      X参数(了解):

    • -Xint            #解释执行
    • -Xcomp       #第一次使用就编译成 本地 的代码
    • -Xmixed      #混合模式(java默认)

      (XX参数之布尔型)重点:jinfo -flag   

      jps -l                           #查看当前运行的Java线程号

      jinfo -flag PrintGCDetails 11111 #查看此线程号的Java程序的某个参数是否开启

    • +PrintGCDetails     #开启打印GC日志 “ +/- ”加减号分别表示开启关闭

      XX参数之 key = value型:

    • -XX:MetaspaceSize=128m           #元空间大小
    • -XX:MaxTenuringThresho=15       #进入老年区的存货年限

      ------------------------------------------------------

    • -XX:PrintFlagInital(了解)  #查看Java环境初始默认值,“ = ”表示默认值,“ := ”表示修改过

      经典面试题:-Xms、-Xmx、怎么解释呢?考察你到底研究过没有!

      1. -Xms 初始堆的大小,等价:-XX:InitialHeapSize

      2. -Xmx 最大堆的大小,等价:-XX:MaxHeapSize

    你常用的项目,发布后配置过JVM调优参数吗?

    • -Xms
    • -Xmx
    • -Xss
    • -Xmn
    • -XX:MetaspsaceSize             #设置元空间的大小,这个在本地内存中
    • -XX:+PrintGCDetails              #打印GC
    • -XX:SurvivoRatio                   #设置新生代中s0/s1空间的比例
      • uintx SurvivorRatio = 8    Eden : s0 : s1 = 8 : 1 : 1
    • -XX:NewRatio                        #设置年轻代与老年代的占比
      • NewRatio = 2   新生代 :老年代 = 1 : 2  默认新生代是整个堆的1/3
    • MaxTenyringThreshold = 15  #进入老年区的存活阈值

    关于对 OOM 的认识

     1 // -Xms8m -Xmx8m -XX:+PrintGCDetails
     2 // java.lang.StackOverflowError 堆栈溢出错误
     3 public class OOM_Demo1 {
     4     public static void main(String[] args) {
     5         a();
     6     }
     7     public static void a(){
     8         a();
     9     }
    10 }
     1 // -Xms8m -Xmx8m -XX:+PrintGCDetails
     2 // java.lang.OutOfMemoryError: Java heap space java堆空间错误
     3 public class OOM_Demo2 {
     4     public static void main(String[] args) {
     5         String str = "hello";
     6         while (true) {
     7             str += str +
     8                     new Random(999999999) +
     9                     new Random(999999999);
    10         }
    11     }
    12 }
     1 // -Xms10m -Xmx10m -XX:MaxDirectMemorySize=5m -XX:+PrintGCDetails
     2 // java.lang.OutOfMemoryError: GC overhead limit exceeded
     3 // GC回收时间过长也会导致OOM
     4 // CPU占用一直100%,GC但是没有什么效果!
     5 public class OOM_Demo3 {
     6     public static void main(String[] args) throws Throwable {
     7         int i = 0;
     8         List<String> list = new ArrayList<String>();
     9 
    10         try {
    11             while (true){
    12                 list.add(String.valueOf(++i).intern());
    13             }
    14         } catch (Throwable e) {
    15             System.out.println("i=>"+i);
    16             e.printStackTrace();
    17             throw e;
    18         }
    19     }
    20 }
     1 // -Xms10m -Xmx10m -XX:MaxDirectMemorySize=5m -XX:+PrintGCDetails
     2 // java.lang.OutOfMemoryError: Direct buffer memory
     3 // 基础缓冲区的错误
     4 public class OOM_Demo4 {
     5     public static void main(String[] args) throws InterruptedException {
     6         System.out.println("配置的MaxDirectMemorySize"+
     7                 VM.maxDirectMemory()/1024/(double)1024+"MB");
     8         TimeUnit.SECONDS.sleep(2L);
     9 
    10         // 故意破环
    11         // ByteBuffer.allocate(); 分配JVM的堆内存,属于GC管辖
    12         // ByteBuffer.allocateDirect(); 分配本地OS内存,不属于GC管辖
    13         ByteBuffer byteBuffer = ByteBuffer.allocateDirect(6*1024*1024);
    14     }
    15 }

    用虚拟机执行,慎用自己电脑执行——会死机

     1 // java.lang.OutOfMemoryError: unable to create  native Thread
     2 // 高并发 ,  unable to create  native Thread这个错误更多的时候和平台有关!
     3 // 1、应用创建的线程太多!
     4 // 2、服务器不允许你创建这么多线程!
     5 public class TDemo {
     6     public static void main(String[] args) {
     7         for (int i = 1; ; i++) {
     8             System.out.println("i=>"+i);
     9             new Thread(()->{
    10                 try {
    11                     Thread.sleep(Integer.MAX_VALUE);
    12                 } catch (InterruptedException e) {
    13                     e.printStackTrace();
    14                 }
    15             },""+i).start();
    16         }
    17     }
    18 }
     1 // -XX:MetaspaceSize=10m -XX:MaxMetaspaceSize=10m
     2 // java.lang.OutOfMemoryError: Metaspace 元空间报错
     3 /*
     4 java8 之后使用元空间代替永久代;本地内存!
     5 1、虚拟机加载类信息
     6 2、常量池
     7 3、静态变量
     8 4、编译后的代码
     9 ..... 
    10 模拟元空间溢出、不断的生成类即可!
    11 */
    12 public class OomDemo {
    13     
    14     static class OOMTest{}
    15 
    16     public static void main(String[] args) throws Throwable {
    17 
    18         int i = 0; // 模拟计数器
    19 
    20         try {
    21             while (true){
    22                 i++;
    23                 // 不断的加载对象! Spring的 cglib;
    24                 Enhancer enhancer = new Enhancer();
    25                 enhancer.setSuperclass(OOMTest.class);
    26                 enhancer.setUseCache(false);
    27                 enhancer.setCallback(new MethodInterceptor() {
    28                     @Override
    29                     public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
    30                         return method.invoke(o,args);
    31                     }
    32                 });
    33                 enhancer.create();
    34             }
    35         } catch (Throwable e) {
    36             System.out.println("i=>"+i);
    37             e.printStackTrace();
    38         }
    39         
    40     }
    41 }

    垃圾收集器(难点!了解即可)

      4种垃圾回收器:

    1. 串行(STW:Stop the World)单线程
      1. STW:意思是执行GC的时候所有线程会停止运行,等待GC完成
    2. 并行(多线程工作,也会导致STW)
    3. 并发(在回收的同时,可以正常执行线程,并行处理,但是如果是单核CPU,只能交替执行!)
    4. G1(将堆内存分割成不同的区域,然后并发的对其进行垃圾回收)

    java -XX:+PrintCommandLineFlags -version  #看默认的垃圾回收器

    Java主要的GC回收器有哪些?(曾经7种,现在6种)

    •  DefNew:默认的新一代(Serial串行)
    • Tenured:老年代(Serial Old)
    • ParNew:并行新一代(并行ParNew)
    • PSYoungGen:并行清除年轻代(Parallel Scavcegn)
    • ParOldGen:并行老年区

     不同的GC回收器的机制不同,使用标准,如何选择:

    • -XX:UseSerialGC                    #单CPU,单机程序,内存小
    • -XX:+UseParallelGC    #多CPU,大吞吐量,后台计算
    • -XX:+UseParNewGC              #多CPU,但是不希望有时间停顿,快速响应   

      垃圾回收器设计原则:尽量少而快的执行GC!

    G1回收器

      -XX:+UseG1GC          #使用G1GC 

      -XX:MaxGCPauseMillis=100    #最大的GC停顿时间单位:毫秒,JVM尽可能的保证停顿小于这个时间

      优点:

      1. 没有内存碎片!
      2. 可以精准控制垃圾回收时间  
  • 相关阅读:
    hadoop 第二次启动 50030端口能打开 50070端口打不开
    hadoop配置(个人总结)
    发布版本化您的应用
    hive 初始化运行流程
    android Content Providers 内容提供者
    hive Cli常用操作(翻译自Hive wiki)
    用于展现图表的50种JavaScript库
    STL list transfer (迁移)实现
    pop_heap算法 (将根节点置于容器尾部后重调heap结构)
    sgi STL源码下载
  • 原文地址:https://www.cnblogs.com/ShallowPen/p/12468887.html
Copyright © 2011-2022 走看看