目录
b站黑马jvm课程学习笔记,第二篇
一、直接内存相关
1.1.定义
1.2 ByteBuffer 作用
使用直接内存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 五种引用![](https://i-blog.csdnimg.cn/blog_migrate/3b0ca664b48b3d38cc06c5e6088ff679.png)
五种引用简单关系图如下:
(1)实线为强引用
(2)当A2和A3没有B对象被强引用时,内存不足时软引用的A2会被回收释放;弱引用的A3一定会被回收释放
(3)当A2和A3被回收后,软引用对象和若引用对象会进入引用队列:
(4)虚引用和终结器引用一定要配合引用队列使用
当ByteBuffer被回收后,虚引用对象进入对列,并且执行Unsafe.freeMemory方法来释放直接内存
(5)终结器引用对象先进入队列,再释放A4对象
2.2.1 软引用应用
/**
* 演示软引用
* -Xmx20m -XX:+PrintGCDetails -verbose:gc
*/
public class Demo2_3 {
private static final int _4MB = 4 * 1024 * 1024;
public static void main(String[] args) throws IOException {
/*List<byte[]> list = new ArrayList<>();
for (int i = 0; i < 5; i++) {
list.add(new byte[_4MB]);
}
System.in.read();*/
soft();
}
public static void soft() {
// list --> SoftReference --> byte[]
List<SoftReference<byte[]>> list = new ArrayList<>();
for (int i = 0; i < 5; i++) {
SoftReference<byte[]> 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<byte[]> 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<SoftReference<byte[]>> list = new ArrayList<>();
// 引用队列
ReferenceQueue<byte[]> queue = new ReferenceQueue<>();
for (int i = 0; i < 5; i++) {
// 关联了引用队列, 当软引用所关联的 byte[]被回收时,软引用自己会加入到 queue 中去
SoftReference<byte[]> 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<byte[]> reference : list) {
System.out.println(reference.get());
}
}
}
2.2.2 弱引用应用
/**
* 演示弱引用
* -Xmx20m -XX:+PrintGCDetails -verbose:gc
*/
public class Demo2_5 {
private static final int _4MB = 4 * 1024 * 1024;
public static void main(String[] args) {
// list --> WeakReference --> byte[]
List<WeakReference<byte[]>> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
WeakReference<byte[]> ref = new WeakReference<>(new byte[_4MB]);
list.add(ref);
for (WeakReference<byte[]> 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(() -> {
ArrayList<byte[]> list = 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动态调整阈值