目录
一、直接内存相关
1.1.定义
1.2 ByteBuffer 作用
1.3文件读写过程
1.3 直接内存溢出和释放
二、垃圾回收相关
2.1 判断是否可以回收
2.2 五种引用编辑
2.2.1 软引用应用
2.2.2 弱引用应用
2.2 垃圾回收算法
b站黑马jvm课程学习笔记,第二篇
一、直接内存相关
1.1.定义
1.2 ByteBuffer 作用
使用直接内存ByteBuffer 读写大文件效率更高
public class Demo1_9 { static final String FROM = "目标文件路径"; static final String TO = "存储路径"; static final int _1Mb = 1024 * 1024; public static void main(String[] args) { io(); // io 用时:1535.586957 1766.963399 1359.240226 directBuffer(); // directBuffer 用时:479.295165 702.291454 562.56592 } private static void directBuffer() { long start = System.nanoTime(); try (FileChannel from = new FileInputStream(FROM).getChannel(); FileChannel to = new FileOutputStream(TO).getChannel(); ) { ByteBuffer bb = ByteBuffer.allocateDirect(_1Mb); while (true) { int len = from.read(bb); if (len == -1) { break; } bb.flip(); to.write(bb); bb.clear(); } } catch (IOException e) { e.printStackTrace(); } long end = System.nanoTime(); System.out.println("directBuffer 用时:" + (end - start) / 1000_000.0); } private static void io() { long start = System.nanoTime(); try (FileInputStream from = new FileInputStream(FROM); FileOutputStream to = new FileOutputStream(TO); ) { byte[] buf = new byte[_1Mb]; while (true) { int len = from.read(buf); if (len == -1) { break; } to.write(buf, 0, len); } } catch (IOException e) { e.printStackTrace(); } long end = System.nanoTime(); System.out.println("io 用时:" + (end - start) / 1000_000.0); } }
1.3文件读写过程
不使用直接内存,此时java缓存区和系统缓存区内得同时存储数据,降低速度
使用直接内存:
1.3 直接内存溢出和释放
内存溢出模拟:
内存释放:
直接内存的释放并非由垃圾回收System.gc()释放,而是由unsafe对象的freeMemory()方法来释放
直接内存的分配和回收原理:
二、垃圾回收相关
2.1 判断是否可以回收
(1)引用计数法
有可能出现两个对象互相引用的情况
(2)可达性分析算法
当对象没有直接或间接被根对象引用时,就可以被当做是垃圾回收
2.2 五种引用
五种引用简单关系图如下:
(1)实线为强引用
(2)当A2和A3没有B对象被强引用时,内存不足时软引用的A2会被回收释放;弱引用的A3一定会被回收释放
(3)当A2和A3被回收后,软引用对象和若引用对象会进入引用队列:
(4)虚引用和终结器引用一定要配合引用队列使用
当ByteBuffer被回收后,虚引用对象进入对列,并且执行Unsafe.freeMemory方法来释放直接内存
(5)终结器引用对象先进入队列,再释放A4对象
2.2.1 软引用应用
public class Demo2_3 {
private static final int _4MB = 4 * 1024 * 1024;
public static void main(String[] args) throws IOException {
soft();
}
public static void soft() {
// list --> SoftReference --> byte[]
List> list = new ArrayList<>();
for (int i = 0; i < 5; i++) {
SoftReference ref = new SoftReference<>(new byte[_4MB]);
System.out.println(ref.get());
list.add(ref);
System.out.println(list.size());
}
System.out.println("循环结束:" + list.size());
for (SoftReference ref : list) {
System.out.println(ref.get());
}
}
}
软引用垃圾回收:
软引用——应用队列
public class Demo2_4 { private static final int _4MB = 4 * 1024 * 1024; public static void main(String[] args) { List> list = new ArrayList<>(); // 引用队列 ReferenceQueue queue = new ReferenceQueue<>(); for (int i = 0; i < 5; i++) { // 关联了引用队列, 当软引用所关联的 byte[]被回收时,软引用自己会加入到 queue 中去 SoftReference ref = new SoftReference<>(new byte[_4MB], queue); System.out.println(ref.get()); list.add(ref); System.out.println(list.size()); } // 从队列中获取无用的 软引用对象,并移除 Reference extends byte[]> poll = queue.poll(); while( poll != null) { list.remove(poll); poll = queue.poll(); } System.out.println("==========================="); for (SoftReference reference : list) { System.out.println(reference.get()); } } }
2.2.2 弱引用应用
public class Demo2_5 {
private static final int _4MB = 4 * 1024 * 1024;
public static void main(String[] args) {
// list --> WeakReference --> byte[]
List> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
WeakReference ref = new WeakReference<>(new byte[_4MB]);
list.add(ref);
for (WeakReference w : list) {
System.out.print(w.get()+" ");
}
System.out.println();
}
System.out.println("循环结束:" + list.size());
}
}
2.3 垃圾回收算法
(1)标记清除算法
优点:速度快
缺点:清除未被引用的内存后,不会对整体内存空间整理,使得内存不连续,碎片化
(2)标记整理算法
优点:没有内存碎片
缺点:整理时,引用对象地址需要变化,花费时间增加
(3)复制算法
优点:不会产生碎片化内存
缺点:需要使用双倍内存
2.4 分代垃圾回收新生代垃圾清理更频繁
老年代当内存不足时才会清理
2.4.1 虚拟机相关参数GC分析
public class Demo2_1 { private static final int _512KB = 512 * 1024; private static final int _1MB = 1024 * 1024; private static final int _6MB = 6 * 1024 * 1024; private static final int _7MB = 7 * 1024 * 1024; private static final int _8MB = 8 * 1024 * 1024; // -Xms20M -Xmx20M -Xmn10M -XX:+UseSerialGC -XX:+PrintGCDetails -verbose:gc -XX:-ScavengeBeforeFullGC public static void main(String[] args) throws InterruptedException { new Thread(() -> { ArrayListlist = new ArrayList<>(); list.add(new byte[_8MB]); list.add(new byte[_8MB]); }).start(); System.out.println("sleep...."); Thread.sleep(1000L); } }
运行输出:
sleep.... [GC (Allocation Failure) [DefNew: 4196K->894K(9216K), 0.0032025 secs][Tenured: 8192K->9084K(10240K), 0.0047001 secs] 12388K->9084K(19456K), [Metaspace: 4211K->4211K(1056768K)], 0.0081122 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] [Full GC (Allocation Failure) [Tenured: 9084K->9028K(10240K), 0.0024288 secs] 9084K->9028K(19456K), [Metaspace: 4211K->4211K(1056768K)], 0.0024576 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] Exception in thread "Thread-0" java.lang.OutOfMemoryError: Java heap space at com.whx.cn.itcast.jvm.t2.Demo2_1.lambda$main$0(Demo2_1.java:20) at com.whx.cn.itcast.jvm.t2.Demo2_1$$Lambda$1/1023892928.run(Unknown Source) at java.lang.Thread.run(Thread.java:748) Heap def new generation total 9216K, used 1293K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000) eden space 8192K, 15% used [0x00000000fec00000, 0x00000000fed43528, 0x00000000ff400000) from space 1024K, 0% used [0x00000000ff500000, 0x00000000ff500000, 0x00000000ff600000) to space 1024K, 0% used [0x00000000ff400000, 0x00000000ff400000, 0x00000000ff500000) tenured generation total 10240K, used 9028K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000) the space 10240K, 88% used [0x00000000ff600000, 0x00000000ffed10b8, 0x00000000ffed1200, 0x0000000100000000) Metaspace used 4747K, capacity 4900K, committed 4992K, reserved 1056768K class space used 529K, capacity 592K, committed 640K, reserved 1048576K Process finished with exit code 0
2.5 垃圾回收器
(1)串行
(2)吞吐量优先
(3)响应时间优先
2.6 G1垃圾回收器 2.6.1垃圾回收阶段
(1)新生代内存布局Young Collection
(2)新生代回收+CM(Young Collection+CM)
(3)混合回收 Mixed Collection
(4)Full GC
(5)新生代跨代引用
(6)Remark
重新标记阶段
在垃圾回收时,收集器处理对象的过程中
黑色:已被处理,需要保留的 灰色:正在处理中的 白色:还未处理的
(7)JDK 8u20字符串去重
(8)JDK 8u40类卸载
(9)JDK 8u60回收巨型对象
(10)JDK 9动态调整阈值