zoukankan      html  css  js  c++  java
  • Java基础教程——垃圾回收机制

    垃圾回收机制

    Garbage Collection,GC

    垃圾回收是Java的重要功能之一。
    |--堆内存:垃圾回收机制只回收堆内存中对象,不回收数据库连接、IO等物理资源。
    |--失去使用价值,即为垃圾:当一个对象不再被引用的时候,就称为垃圾。
    |--无法控制:垃圾回收的时间无法控制,系统会在“合适的时间”进行垃圾回收。
    |--强制回收:System.gc():通知系统进行垃圾回收,但是系统是否回收还是不确定。

    GC算法:

    • 根搜索算法:设立若干种根对象,当任何一个根对象到某一个对象均不可达时,则认为这个对象是可以被回收的

    • 标记-清除(Mark-Sweep)算法:标记阶段,首先通过根节点,标记所有从根节点开始的可达对象。(未被标记的对象就是垃圾对象);清除阶段,清除所有未被标记的对象。

    垃圾收集器(G1):
    Garbage First。比较新的的垃圾回收技术。JDK7时引入,弱化分代,强调分区。G1算法将堆划分为若干个区域(Region),清理垃圾时有类似于硬盘整理的操作,不会有碎片问题。

    finalize()方法:

    • 对象被销毁之前调用。
    • finalize方法由垃圾回收机制调用,因此调用情况具有不确定性。
    • 当JVM执行finalize()时出现了异常,垃圾回收机制不会报告异常,程序继续执行。
    public class Test垃圾回收 {
    	public static void main(String[] args) {
    		for (int i = 0; i < 10; i++) {
    			new Garbage(i);
    		}
    		// 强制垃圾回收
    		System.gc();
    	}
    }
    class Garbage {
    	private int id;
    	public Garbage(int id) {
    		this.id = id;
    	}
    	@Override
    	protected void finalize() throws Throwable {
    		System.out.println("被回收:" + id);
    	}
    }
    

    被回收:6
    被回收:1
    被回收:0
    被回收:4
    被回收:3
    被回收:2
    被回收:9

    (↑每次执行结果不一样)

    对象的引用

    强引用(StrongReference)。

    软引用(SoftReference):内存不足时会被回收。可用于实现缓存。

    弱引用(WeakReference):不管内存够不够,都会被回收。弱引用可以用于构建非敏感区域的缓存。

    import java.lang.ref.WeakReference;
    // 弱引用(WeakReference):不管内存够不够,都会被回收。
    // 弱引用可以用于构建非敏感区域的缓存。
    public class TestWeakReference {
    	public static void main(String[] args) throws Exception {
    		String str = new String("圣僧东土到此,有些什么人事送我们?快拿出来,好传经与你去。");
    		// 弱引用:当系统垃圾回收机制运行时,不管系统内存是否足够,总会回收该对象所占用的内存。
    		WeakReference<String> wr = new WeakReference<String>(str);
    		str = null;
    		// get():获取被引用的对象
    		System.out.println("弱引用:" + wr.get());
    		System.out.println(wr.isEnqueued());
    		// 强制垃圾回收
    		System.gc();
    		// 再次取出弱引用的对象
    		System.out.println("弱引用:" + wr.get());
    		System.out.println(wr.isEnqueued());
    	}
    }
    
    弱引用:圣僧东土到此,有些什么人事送我们?快拿出来,好传经与你去。
    false
    弱引用:null
    false
    

    虚引用(PhantomReference):虚引用必须和引用队列(ReferenceQueue)联合使用,主要用于跟踪被垃圾回收的状态。(phantom:幻影、错觉)

    import java.lang.ref.PhantomReference;
    import java.lang.ref.ReferenceQueue;
    // 虚引用(PhantomReference):
    // 虚引用必须和引用队列(ReferenceQueue)联合使用,
    // 主要用于跟踪被垃圾回收的状态。(phantom:幻影、错觉)
    public class TestPhantomReference {
    	public static void main(String[] args) throws Exception {
    		String str = new String("圣僧东土到此,有些什么人事送我们?快拿出来,好传经与你去。");
    		// 引用队列
    		ReferenceQueue refQue = new ReferenceQueue();
    		PhantomReference pRef = new PhantomReference(str, refQue);
    		str = null;
    		// 虚引用的get()不到,结果为null
    		System.out.println("虚引用:" + pRef.get());
    		;
    		System.out.println("---强制垃圾回收---");
    		System.gc();
    		System.runFinalization();// 通知系统进行系统清理
    		// 垃圾回收之后,虚引用将被放入引用队列中
    		System.out.println("refQue.poll():" + (refQue.poll() == pRef));
    	}
    }
    
    虚引用:null
    ---强制垃圾回收---
    refQue.poll():true
    

    直接内存

    堆外内存,直接受操作系统管理。

    作用:

    (1)减少垃圾回收

    (2)提升IO效率

    java.nio.ByteBuffer.allocateDirect(capacity);

    import java.nio.ByteBuffer;
    //“直接内存”VS“堆内存” 
    // 直接内存分配慢:当频繁申请到一定量时尤为明显
    // 直接内存读写块:在多次读写操作的情况下差异明显
    public class ByteBufferCompare {
    	public static void main(String[] args) {
    		// 分配比较(100万次已看出明显差别)
    		compareAllocate(100_0000L, "直接内存");
    		compareAllocate(100_0000L, "堆内存");
    		// 读写比较(1亿次可看出差别)
    		compareIo(1_0000_0000L, "直接内存");
    		compareIo(1_0000_0000L, "堆内存");
    	}
    	// 分配空间比较
    	public static void compareAllocate(long times, String memoryType) {
    		// // 操作次数
    		long _start = System.currentTimeMillis();
    		ByteBuffer buffer = null;
    		for (int i = 0; i < times; i++) {
    			if ("直接内存".equals(memoryType)) {
    				buffer = ByteBuffer.allocateDirect(2);
    			} else {
    				buffer = ByteBuffer.allocate(2);
    			}
    		}
    		long _end = System.currentTimeMillis();
    		System.out.println(times + "次内存分配:" + memoryType + ":"
    				+ (_end - _start));
    	}
    	// 读写性能比较
    	public static void compareIo(long times, String memoryType) {
    		// 先分配空间
    		ByteBuffer buffer = null;
    		int capacity = 2 * (int) times;
    		if ("直接内存".equals(memoryType)) {
    			buffer = ByteBuffer.allocateDirect(capacity);
    		} else {
    			buffer = ByteBuffer.allocate(capacity);
    		}
    		// 再测试读写时间
    		long _start = System.currentTimeMillis();
    		for (int i = 0; i < times; i++) {
    			// putChar(char value) 用来写入 char 值
    			buffer.putChar('a');
    		}
    		// 将缓存字节数组的指针设置为数组的开始序列(即数组下标0)
    		buffer.flip();
    		for (int i = 0; i < times; i++) {
    			buffer.getChar();
    		}
    		long _end = System.currentTimeMillis();
    		System.out.println(times + "次读写:" + memoryType + ":" + (_end - _start));
    	}
    }
    
    100 0000次内存分配:直接内存:459
    100 0000次内存分配:堆内存:15
    
    1 0000 0000次读写:直接内存:174
    1 0000 0000次读写:堆内存:290
    
  • 相关阅读:
    《Linux Device Drivers》第十二章 PCI司机——note
    Swift开放StatsD后上传数据的出现,出现退换货503的Bug
    google login page
    Use GraceNote SDK in iOS(一)通过序列化GDO查询专辑封面
    【人在职场】能力与价值
    HDU 5067-Harry And Dig Machine(DFS)
    LeetCode:Merge Two Sorted Lists
    HTML5硕士学习笔记
    通过设置注册表隐藏桌面图标
    SharePoint 要一个多行文本类型字段为特殊类型的链接
  • 原文地址:https://www.cnblogs.com/tigerlion/p/11182825.html
Copyright © 2011-2022 走看看