- 前言
- 一、Runtime.getRuntime().gc()
- 1.与System.gc() 对比
- 2.官方说明
- 二、Runtime.getRuntime().runFinalization()
- 1.与System.runFinalization() 对比
- 2.官方说明
- 3.为什么不推荐使用finalize()
- 三、测试GC
- 1.查看当前jvm占用内存
- 总结
前言
很多小伙伴可能没用过甚至没见过这两个方法,但作为一名 java 开发仔,你肯定见过 System.gc();
带着这个想法,我们接着往下看
一、Runtime.getRuntime().gc() 1.与System.gc() 对比
我们点开 System.gc() 的源码,发现里面其实就是调用 Runtime.getRuntime().gc() ,所以他们两者是等效的。只是我们平时习惯使用 jdk 给我们提供的 System 类
Runtime.getRuntime().gc() 方法,官方给出的注释是这样的:
翻译过来就是:
二、Runtime.getRuntime().runFinalization() 1.与System.runFinalization() 对比在 Java 虚拟机中运行垃圾收集器。
调用该gc方法表明 Java 虚拟机花费精力回收未使用的对象,以使它们当前占用的内存可供 Java 虚拟机重用。当控制从方法调用返回时,Java 虚拟机已尽最大努力从所有未使用的对象中回收空间。无法保证此工作将回收任何特定数量的未使用对象,回收任何特定数量的空间,或在任何特定时间(如果有的话)在方法返回之前或永远完成。也不能保证这种努力将确定任何特定数量的对象的可达性变化,或者任何特定数量的Reference 对象将被清除和排队。
调用System.gc()实际上等同于调用:Runtime.getRuntime().gc()
同样,我们点开 System.runFinalization() 的源码,发现里面其实就是调用Runtime.getRuntime().runFinalization() ,所以他们两者是等效的。
Runtime.getRuntime().runFinalization() 方法,官方给出的注释是这样的:
翻译过来就是:
运行任何等待终结的对象的终结方法。调用此方法表明 Java 虚拟机将努力运行finalize已发现已丢弃但其finalize 方法尚未运行的对象的方法。当控制从方法调用返回时,Java 虚拟机已尽最大努力完成所有未完成的终结。
调用System.runFinalization()实际上等同于调用: Runtime.getRuntime().runFinalization()
Runtime.getRuntime().runFinalization() 是和 object 的 finalize() 搭配使用的
但是,从 Java9 开始,object 的 finalize() 方法已被标注为 @Deprecated 过期了
所以,已经不推荐再使用 Runtime.getRuntime().runFinalization() 进行gc 了
注意:在最新的 java18 中,finalize() 和 runFinalization() 已经被标记为弃用了,,不再是简单的过期了,未来可能会被删除
3.为什么不推荐使用finalize()- 调用时机不确定
虽然finalize()方法早晚会被调用到,但这种调用时机的不可控性可能会导致资源迟迟不被释放而出现系统级异常。因为计算机的资源有是限的,当明确要释放某些资源时(比如上面例子中reader所掌控的一系列资源),应该使用其它的办法让这些资源立即释放 - 影响代码的可移植性
因为每种JVM内置的垃圾回收算法都是不同的,所以可能在你的JVM里,你辛辛苦苦编写的使用finalize方法的案例运行的很好,但移植到不同的JVM中时,很有可能会崩溃的一塌糊涂! - 成本较高
如果某个类重载了finalize方法且在方法内部实现了一些逻辑,那么JVM在构造或销毁这个类的对象之前,会做很多额外的工作。很明显,如果一个类没有重载finalize方法,那么销毁时只要将堆中的内存处理一下就可以了,而如果重载了finalize方法的话,就要执行finalize方法,万一执行过程中再出现点异常或错误,那消耗的成本就更高了。 - 异常丢失
万一fianlize方法中抛出了异常,那么finalize会终止运行,而抛出的这个异常也会被舍弃,最终会让对象实例处于一种半销毁半存活的僵尸状态,导致意想不到的后果!
该片段引用自:
三、测试GChttps://www.bilibili.com/read/cv4055723
可能我们都是八股文的职业选手,精通各种技术框架的底层原理,熟练背诵各种 sql 优化和 gc 原理,当然,这是在面试的情况下,实际开发中,我们大部分人都是不曾接触这些的,也就面试拿来装一下。
但是,为了让我们更加直观的感受到 GC 带来的效果,也算是我们一次简单的 GC 入门案例,我用实际代码带大家接触下神秘的 GC:
1.查看当前jvm占用内存java 代码在运行时会将各种信息放进 mbeanServer 管理 ,我们可以从中获取
// 获取 mbeanServer,jvm运行时会将操作系统内存信息放进去,ObjectName唯一对应:java.lang:type=OperatingSystem MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer(); ObjectName objectName = new ObjectName("java.lang:type=OperatingSystem"); // OS的最大内存 Long totalPhysicalMemorySize = (Long)mBeanServer.getAttribute(objectName, "TotalPhysicalMemorySize"); // OS的空闲内存 Long freePhysicalMemorySize = (Long)mBeanServer.getAttribute(objectName, "FreePhysicalMemorySize"); // JVM的使用内存 Long committedVirtualMemorySize = (Long)mBeanServer.getAttribute(objectName, "CommittedVirtualMemorySize"); Long totalRAM = totalPhysicalMemorySize / 1024 / 1024; Long freeRAM = freePhysicalMemorySize / 1024 / 1024; Long jvmRAM = committedVirtualMemorySize / 1024 / 1024; System.out.println("操作系统总内存:" + totalRAM + " MB"); System.out.println("操作系统的内存使用了:" + (totalRAM - freeRAM) + " MB"); System.out.println("jvm使用的内存:" + jvmRAM + " MB");
总结
欢迎指出我的错误!