必须掌握: -XX:+PrintFlagsInitial -XX:+PrintFlagsFinal -XX:+PrintCommandLineFlags 常用参数: -Xms:初始化大小内存 -Xmx:最大分配内存 -Xss:设置单个线程的大小 -Xmn:设置年轻代大小 -XX:MetaspaceSize :元空间(Java8以后替代永久代) -XX:+PrintGCDetails -XX:SurvivorRatio -XX:NewRatio -XX:MaxTenuringThreshold :设置垃圾最大年龄 Java默认是强引用
强引用:JVM就算出现OOM也不会对该对象回收,死也不会回收 造成内存泄露 package com.itguigu; //强引用 public class StrongReferenceDemo { public static void main(String[] args) { Object obj1 = new Object();//这样定义的默认就是强引用 Object obj2 = obj1;//obj2引用赋值 obj1 = null;//置空 System.gc(); System.out.println(obj1);//null /* 因为是强引用:所以obj1被清理,与obj2没毛关系 */ System.out.println(obj2);//java.lang.Object@3f99bd52 } } 软引用:内存足够,则不收;内存不够,需要收;来保证不会发生OOMpackage com.itguigu;
import java.lang.ref.SoftReference;
//软引用 public class SoftReferenceDemo { private byte[] bytes;
/** * 内存够用就保留,不够就回收 */ public static void softRef_Memory_Enough(){ Object o1 = new Object();//强引用 //软引用 SoftReference<Object> softReference = new SoftReference<>(o1); System.out.println(o1); System.out.println(softReference.get()); o1 = null; System.gc(); System.out.println(o1);//null //内存够用,软引用不会被回收 System.out.println(softReference.get());//java.lang.Object@3f99bd52 } /** * 超出内存,软引用被回收 * * -Xms5m -Xmx5m -XX:+PrintGCDetails */ public static void softRef_Memory_NotEnough(){ Object o1 = new Object();//强引用 //软引用 SoftReference<Object> softReference = new SoftReference<>(o1); System.out.println(o1); System.out.println(softReference.get()); o1 = null; System.gc(); try { //让内存空间不够 byte[] bytes = new byte[30 * 1024 * 1024]; } catch (Exception e) { e.printStackTrace(); } finally { System.out.println(o1);//null //内存不够用,软引用会被回收 System.out.println(softReference.get());//null } } public static void main(String[] args) { softRef_Memory_Enough(); System.out.println(); System.out.println(); System.out.println(); softRef_Memory_NotEnough(); } } 弱引用:无论内存是否够用,只要垃圾回收到来,一律回收 * 如果每次读取图片都从硬盘读取则会严重影响性能, * 如果一次全部加载到内存中又可能造成内存溢出; 使用软引用: 用一个HashMap来保存图片路径和相应图片对象关联的软引用之间的映射关系,在内存不足时,JVM会自动回收这些缓存图片对象所占用的空间,从而有效的避免了OOM的问题。 Mao<String,SoftReference<Bitmap>> imageCache = new HashMap<String,SoftReference<Bitmap>>(); package com.itguigu; import java.lang.ref.WeakReference; /** * 弱引用:只要垃圾回收到来,就会被回收 */ public class WeakReferenceDemo { public static void main(String[] args) { Object o1 = new Object(); WeakReference<Object> weakReference = new WeakReference<>(o1); System.out.println(o1); System.out.println(weakReference.get()); o1 = null; System.gc(); System.out.println("============="); System.out.println(o1);//null System.out.println(weakReference.get());//null } } 谈谈WeakHashMap的使用?—>可以做高速缓存
package com.itguigu; import java.util.HashMap; import java.util.WeakHashMap; /** * WeakHashMap */ public class WeakHashMapDemo { public static void main(String[] args) { myHashMap(); System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); myWeakHashMap(); } private static void myWeakHashMap() { WeakHashMap<Integer,String> map = new WeakHashMap<>(); Integer key = new Integer(2); String value = "HashMap"; map.put(key,value); System.out.println(map);//{2=HashMap} key = null; System.out.println(map);//{2=HashMap} System.gc(); System.out.println(map);//{}弱引用,被回收 } private static void myHashMap() { HashMap<Integer,String> map = new HashMap<>(); Integer key = new Integer(1); String value = "HashMap"; map.put(key,value); System.out.println(map);//{1=HashMap} key = null; System.gc(); System.out.println(map);//{1=HashMap}默认是强引用,map还是map } } 虚引用:幽灵引用(任何时候都可能被回收) 必须和引用队列(ReferenceQueue)联合使用 只要用于跟踪对象被垃圾回收的状态。 package com.itguigu; import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; import java.util.HashMap; import java.util.WeakHashMap; /** * WeakHashMap */ public class ReferenceQueuDemo { public static void main(String[] args) throws InterruptedException { Object o1 = new Object(); ReferenceQueue<Object> referenceQueue = new ReferenceQueue(); WeakReference<Object> weakReference = new WeakReference<>(o1,referenceQueue); System.out.println(o1);//java.lang.Object@3f99bd52 System.out.println(weakReference.get());//java.lang.Object@3f99bd52 System.out.println(referenceQueue.poll());//null System.out.println(">>>>>>>>>>>>>>>>>>>>>"); o1 = null; System.gc(); Thread.sleep(500); System.out.println(o1);//null System.out.println(weakReference.get());//null System.out.println(referenceQueue.poll());//java.lang.ref.WeakReference@4f023edb 回收之前被放在了引用队列 } } ----------------|StackOverflowError: //java.lang.StackOverflowError public class StackOverflowErrorDemo { public static void main(String[] args) { myStackOverflow(); } private static void myStackOverflow() { myStackOverflow(); } }
---------------|OutOfMemoryError: package com.itguigu; import java.util.Random; /** * -Xms10m -Xmx10m * Exception in thread "main" java.lang.OutOfMemoryError: Java heap space */ public class JavaHeapSpaceDemo { public static void main(String[] args) { String str = "atguigu"; while (true){ str += str + new Random().nextInt(1111111) + new Random().nextInt(22222222); str.intern(); } } } ----------------|OutofMemoryError ----------------| GC算法(引用计数/复制/标清/标整)是内存回收的方法论,垃圾收集器就是对算法的落地实现
4种垃圾回收算法思想----4种垃圾收集器 目前还没有完美的收集器出现,更没有万能的收集器,只是针对具体应用最合适的收集器,进行分代收集。 4种垃圾收集器: Serial(串行回收):为单线程环境设计且只使用一个线程进行垃圾回收,会暂停所有的用户线程,所以不适合服务器环境。 parallel(并行回收):多个垃圾收集线程并行工作,用户线程暂停,适用于科学计算/大数据处理首台处理等弱交互。 CMS(并发标记清除):用户线程和垃圾收集线程同时执行(不一定是并行,可能交替执行),不需要停顿用户线程,互联网公司多用它,适用对响应时间有要求的场景。 G1:G1垃圾回收期将堆内存分割成不同的区域然后并发的对其进行垃圾回收。 ZGC(java11):=======新生代》》》》》》》》只要新生代被配置,老年代会自动被激活 开启串行参数:-XX:+UseSerialGC 开启后会使用:Serial(Young区)+Serial Old(Old区)的收集器组合 表示:新生代、老年代都会使用串行回收收集器,新生代使用复制算法,老年代使用标记整理算法。
开启并行参数:-XX:+UseParNewGC 启用ParNew收集器,只影响新生代的收集,不影响老年代, 开启后悔使用:ParNew(Young区)+Serial Old(Old区)的收集器组合,新生代使用复制算法,老年代使用标记整理算法。 但是ParNew+Tenured的搭配,java8已经不再被推荐 备注:-XX:+UseParNewGC 限制线程数量,默认开启和CPU数目相同的线程数 开启并行回收参数(java8默认):-XX:UseParallelGC或-XX:+UseParallelOldGC(可相互激活) 使用Parallel Scanvenge收集器 开启后:新生代使用复制算法,老年代使用标记-整理算法 注意:-XX:ParallelGCThreads=数字N 表示启动多少个GC线程 cpu>8 N=5/8 cpu<8 N=实际个数 重点: 可控制的吞吐量(Thoughput=运行用户代码时间/(运行代码时间+垃圾回收时间),比如:程序运行99分钟,垃圾回收1分钟,吞吐量就是99%)。高吞吐量意味着高效的利用CPU的时间,它多用于后台运算而不需要太多交互的任务。=======老年代》》》》》》》》
………… 并发标记清除GC(CMS): 4步:初始标记(CMS initial mark) 并发标记(CMS concurrent mark):和用户线程一起工作 重新标记(CMS remark) 并发清除(CMS concurrent sweep):和用户线程一起工作 优缺点: 优:并发收集低停顿 缺:对cpu资源压力大;采用标记清除算法会导致大量碎片 组合的选择: 1->单CPU或小内存,单机程序 -XX:+UseSerialGC 2->多CPU,需要最大吞吐量,如后台计算型应用 -XX:+UseParallelGC 或者 -XX:UseParallelOldGC 3->多CPU,追求低停顿时间,需要快速响应如互联网应用 -XX:+UseConcMarkSweepGC -XX:+ParNewGC