• GC(Garbage Collection)


    GC(Garbage Collection)

    GC背景

    ​  创建对象会消耗内存,如果不回收对象占用的内存,内存使用率会越来越高,最终出现OutOfMemoryError(OOM)
    ​  在C++中专门有一个"析构函数"来回收对象占用的内存,Java有一个专门的GC线程,定时执行清理对象占用的内存

    ​  从JDK1.3开始到现在:GC经历了4个阶段的变化

    ​​    1、串行垃圾收集

    ​​    2、并行垃圾收集

    ​​    3、并发垃圾收集

    ​​    4、G1垃圾收集(Garbage First)

    内存分配

    JVM执行程序,将内存分为5块:

    ​  程序计数器:记录当前程序里面的指令执行的状态。

    ​  JVM栈:每个方法一旦调用,就会将该方法入栈,每个方法都有自己的局部变量列表,局部方法列表存储了对象的引用。

    ​  ​ 注意:一旦方法不停的入栈,占满了栈内存的空间就会出现StackOverflowError错误。

    ​  本地方法栈:Java由C++ 演变而来,建立在C++基础上的,C++提供了很多dll(动态链接库)给Java调用,主要加载C++的DLL,和我们程序没有多大关联。

    ​  堆栈:所有new产生的对象都在堆中,GC主要就是回收堆栈内存对象占用的内存空间。

    ​  方法区:当一个类成功加载到JVM,JVM就会存储该类的Class信息(package、类型信息class、属性信息field、方法信息method、构造方法信息、静态属性和方法信息)。

    堆内存配置

    ​  -Xmx 最大堆内存 默认值:整个计算机物理内存的1/4 4G 最大值64G
    ​ 建议不要超过计算机物理内存的1/2

    ​  -Xms 初始堆内存 默认值:整个计算机物理内存的1/64 256M
    注意:工作中上面两个参数的配置最好一致(可以减少垃圾收集的频率)

    ​  -Xmn 设置堆内存年轻代大小 整个堆内存3/8

    ​  -Xss 占内存每个线程的大小 默认1M 128k

    ​  -XX:+PrintGCDetails 打印GC信息

    以上JVM参数在哪里配置???

    ​  1. 可以在Eclipse启动之前配置 Eclipse.ini(软件启动项的根目录)

    ​  ​  -XX:+UseG1GC 使用G1方式进行垃圾收集

    ​  ​  XX:+UseStringDeduplication主要是用来消除长时间存活的重复字符串对象 ,注意它只能用在G1垃圾收集

    ​  2. Eclipse配置JDK的时候设置

    ​  串行
    ​  ​  -Xmx4096m -Xms4096m -Xmn1536m -XX:+PrintGCDetails

    ​  并行
    ​​  ​  -Xmx4096m -Xms4096m -Xmn1536m -XX:+UseParallelGC -XX:+UseParallelOldGC -XX:ParallelGCThreads=2 -XX:+PrintGCDetails
    ​  ​  设置垃圾收集为并行收集,通常用于服务器端,场景:多个客户端连接一个服务器,此时服务器会采用并行垃圾收集。

    ​  并发
    ​  ​  -XX:+UseConcMarkSweepGC 并发垃圾收集
    ​  ​  -Xmx4096m -Xms4096m -Xmn1536m -XX:+UseConcMarkSweepGC -XX:+PrintGCDetails

    ​  G1
    ​  ​  -XX:+UseG1GC 使用G1作为垃圾收集
    ​​  ​  XX:G1HeapRegionSize=16m 设置每个区块大小
    ​  ​  -Xmx4096m -Xms4096m -XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:+PrintGCDetails

    ​  将堆内存划分为不连续分配的空间 ,将你的堆内存划分为1个或者多个区块(Region),每个区块分配的内存大小在(1m、2m、4m、8m、16m、32m)之间

    	@Test
    	public void testStringBuffer() {
    		for(;;) {
    			byte[] by = new byte[1*1024*1024];
    		}
    	}
    	
    	@Test
    	public void testString() {
    		String str="";
    		for(int i=0;i<500000;i++) {
    			str+="i";
    		}
    	}
    	
    	/**
    	 * -Xmx16m -Xms16m -Xmn6m -XX:+PrintGCDetails
    	 * 会出现OutOfMemoryError:因为垃圾收集的频率赶不上创建对象的频率
    	 * 随便编写一个程序,如何让他永远不死(OutOfMemoryError,StackOverflowError),随便编写一个程序让他立马死掉
    	 * javac命令编译程序  java命令运行程序  在bin目录下
    	 * 你平时在工作中除了使用上面两个命令,还使用过哪些命令?
    	 * javap 反编译字节码
    	 * jconsole 监控程序
    	 * jvisualvm 监控程序
    	 * javadoc命令
    	 */
    	@Test
    	public void testByte() {
    		for(;;) {
    			//每次循环分配10MB的内存
    			byte[] by =new byte[1024*1024*1024];
    		}
    	}
    

    ​  ​  小结:eden(伊甸区永远都是存储最新鲜的对象,也就是刚刚new出的对象),一旦伊甸区的使用率到达一个阀值(85%),启动GC,回收年轻代的对象将伊甸区不活动的对象转移到幸存区,当幸存区到达阀值,再次做垃圾回收,如果回收失败,将对象放入老年代,如果老年代到达阀值,会做full gc(全量回收),如果回收失败OOM(OutOfMemory)错误.

    ​  G1垃圾收集

    ​  ​  [GC (Allocation Failure) [PSYoungGen: 1179648K->1270K(1376256K)] 1179648K->1278K(3997696K), 0.0011735 secs][Times: user=0.00 sys=0.00, real=0.00 secs]

    ​  GC启动垃圾收集

    ​  ​  Allocation Failure: 分配空间失败
    ​  ​  PSYoungGen: GC回收年轻代的内存

    ​  ​  1179648K->1270K(1376256K)
    ​  ​  1376256K 年轻代分配的内存空间
    ​  ​  1179648K 垃圾收集之前年轻代使用的空间
    ​  ​  ​ 年轻代内存使用率86% 将进行垃圾收集(minor 最轻量级的垃圾收集)
    ​  ​  1270K 垃圾收集之后年轻代使用的空间

    ​  ​  1179648K->1278K(3997696K)
    ​  ​  3997696K:表示整个堆内存(年轻代+老年代)的总空间
    ​  ​  1179648K:表示整个堆内存(年轻代+老年代)的在垃圾收集之前的使用空间
    ​  ​  1278K:表示整个堆内存(年轻代+老年代)的在垃圾收集之后的使用空间

    Heap
    //年轻代总空间 1571328K ,使用空间837686K 
     PSYoungGen      total 1571328K, used 837686K [0x0000000760000000, 0x00000007c0000000, 0x00000007c0000000)
    //表示 eden space年轻代的伊甸区使用空间 1569792K ,使用率837686/1569792=53%                                     
      eden space 1569792K, 53% used [0x0000000760000000,0x0000000793143430,0x00000007bfd00000)
     //from space表示 年轻代的幸存1区分配了1536k,使用率52%                               
      from space 1536K, 52% used [0x00000007bfd00000,0x00000007bfdca510,0x00000007bfe80000)
    // to   space 表示 年轻代的幸存2区分配了1536k,使用率0%                             
      to   space 1536K, 0% used [0x00000007bfe80000,0x00000007bfe80000,0x00000007c0000000)
    //ParOldGen       total老年代分配的空间2621440K  使用了952K                           
     ParOldGen       total 2621440K, used 952K [0x00000006c0000000, 0x0000000760000000, 0x0000000760000000)
      object space 2621440K, 0% used [0x00000006c0000000,0x00000006c00ee0a0,0x0000000760000000)
     Metaspace       used 4511K, capacity 4990K, committed 5248K, reserved 1056768K
      class space    used 532K, capacity 562K, committed 640K, reserved 1048576K
    
    //Full GC 表示全量垃圾收集[年轻代和老年代的内存]
    // 40369/40960=98% 老年代使用率到达98% 危险:老年代如果回收失败就会出现OutOfMemoryError
    [Full GC (Ergonomics) [PSYoungGen: 404K->0K(24064K)] [ParOldGen: 40369K->1397K(40960K)] 40774K->1397K(65024K), [Metaspace: 4497K->4497K(1056768K)], 0.0029315 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
    

    ​  3. 在你编写程序的启动类上设置

  • 相关阅读:
    详细介绍Linux shell脚本基础学习(二)
    MySQL主从复制
    推荐一款好用的jquery弹出层插件——wbox
    Jenkins安装插件下载失败
    如何在 Amazon RDS 中部署 MySQL 数据库实例
    VMware vSphere 6 Enterprise Plus 永久激活许可证亲测可用
    使用 convert database 命令进行 RMAN 跨平台迁移(12C>19C)
    hbase用户授权
    hbase move region
    hbase表集群间数据同步 hbase replication
  • 原文地址:https://www.cnblogs.com/lyang-a/p/11530781.html
Copyright © 2020-2023  润新知