//m = 3时,即 3M的 byte 数组定义时,申请的内存空间不足 Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at com.example.jvm.reference.JvmReferenceTest.testStrongReference(JvmReferenceTest.java:27) at com.example.jvm.reference.JvmReferenceTest.main(JvmReferenceTest.java:23)
Free memory after add list size: 1 is 0MB Free memory after add list size: 2 is 1MB Free memory after add list size: 3 is 1MB Free memory after add list size: 4 is 1MB Free memory after add list size: 5 is 1MB Free memory after add list size: 6 is 1MB Free memory after add list size: 7 is 1MB Free memory after add list size: 8 is 1MB Free memory after add list size: 9 is 1MB Free memory after add list size: 10 is 1MB Current memory use: 2MB Total memory is: 3MB null null null null null null null null null [B@47d384ee
可以看出内存不足时,自动释放了。最后的 list 集合中只保留了一个 byte 数组,刚好时 2M的大小。
如果略微调整下 buff 变量的位置,会发生一件很有意思的事情。
privatestaticvoidtestSoftReference(int m){ // 声明为方法内可见的局部全局变量 byte[] buff = null; List<SoftReference<Object>> list = new ArrayList<>(); for (; m > 0; m--) { buff = newbyte[1024 * 1024 * 2]; SoftReference<Object> sr = new SoftReference<>(buff); list.add(sr); System.out.println("Free memory after add list size: " + list.size() + " is " + getFreeMemory() + "MB"); } System.out.println("Current memory use: " + (getTotalMemory() - getFreeMemory()) + "MB"); System.out.println("Total memory is: " + getTotalMemory() + "MB"); //输出 for (SoftReference<Object> item : list) { System.out.println(item.get()); } System.out.println("--------------------------------"); }
Free memory after add list size: 1 is 0MB Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at com.example.jvm.reference.JvmReferenceTest2.testSoftReference(JvmReferenceTest2.java:69) at com.example.jvm.reference.JvmReferenceTest2.main(JvmReferenceTest2.java:30)
privatestaticvoidtestWeakReference(int m){ List<WeakReference<Object>> list = new ArrayList<>(); for (; m > 0; m--) { byte[] buff = newbyte[1024 * 1024 * 2]; WeakReference<Object> sr = new WeakReference<>(buff); list.add(sr); System.out.println("Free memory after add list size: " + list.size() + " is " + getFreeMemory() + "MB"); } System.out.println("Current memory use: " + (getTotalMemory() - getFreeMemory()) + "MB"); System.out.println("Total memory is: " + getTotalMemory() + "MB"); System.gc(); //输出 for (WeakReference<Object> item : list) { System.out.println(item.get()); } System.out.println("--------------------------------"); }
日志
Free memory after add list size: 1 is 0MB Free memory after add list size: 2 is 1MB Free memory after add list size: 3 is 1MB Free memory after add list size: 4 is 1MB Free memory after add list size: 5 is 1MB Free memory after add list size: 6 is 1MB Free memory after add list size: 7 is 1MB Free memory after add list size: 8 is 1MB Free memory after add list size: 9 is 1MB Free memory after add list size: 10 is 1MB Current memory use: 2MB Total memory is: 3MB null null null null null null null null null null --------------------------------
/** * Returns this reference object's referent. Because the referent of a * phantom reference is always inaccessible, this method always returns * <code>null</code>. * * @return <code>null</code> */ public T get(){ returnnull; }
/** * Creates a new phantom reference that refers to the given object and * is registered with the given queue. * * <p> It is possible to create a phantom reference with a <tt>null</tt> * queue, but such a reference is completely useless: Its <tt>get</tt> * method will always return null and, since it does not have a queue, it * will never be enqueued. * * @param referent the object the new phantom reference will refer to * @param q the queue with which the reference is to be registered, * or <tt>null</tt> if registration is not required */ publicPhantomReference(T referent, ReferenceQueue<? super T> q){ super(referent, q); }
for (int i = 0; i < 100000; i++) { inputStream = new FileInputStream("/Users/robin/a.txt"); outputStream = new FileOutputStream("/Users/robin/b.txt"); FileOperation operation = new FileOperation(inputStream, outputStream); operation.operate(); TimeUnit.MILLISECONDS.sleep(100);
privatevoidexpungeStaleEntries(){ for (Object x; (x = queue.poll()) != null; ) { synchronized (queue) { @SuppressWarnings("unchecked") Entry<K,V> e = (Entry<K,V>) x; int i = indexFor(e.hash, table.length); Entry<K,V> prev = table[i]; Entry<K,V> p = prev; while (p != null) { Entry<K,V> next = p.next; if (p == e) { if (prev == e) table[i] = next; else prev.next = next; // Must not null out e.next; // stale entries may be in use by a HashIterator e.value = null; // Help GC size--; break; } prev = p; p = next; } } } }
finalclassFinalizerextendsFinalReference<Object> { /* Package-private; must be in same package as the Reference class */ // 引用队列 privatestatic ReferenceQueue<Object> queue = new ReferenceQueue<>(); privatestatic Finalizer unfinalized = null; privatestaticfinal Object lock = new Object(); // 链表结构 private Finalizer next = null, prev = null;
Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。
Sublime Text
Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。