有没有一种类似于C free()
函数的释放Java内存的方法?还是将对象设置为null并依靠GC是唯一的选择?
有没有一种类似于C free()
函数的释放Java内存的方法?还是将对象设置为null并依靠GC是唯一的选择?
Answers:
Java使用托管内存,因此分配内存的唯一方法是使用new
运算符,而释放内存的唯一方法是依靠垃圾回收器。
该内存管理白皮书(PDF)可能有助于解释发生了什么。
您还可以致电System.gc()
建议垃圾收集器立即运行。但是,Java Runtime做出最终决定,而不是您的代码。
根据Java文档,
调用gc方法表明,Java虚拟机将花费更多精力来回收未使用的对象,以使它们当前占用的内存可用于快速重用。当控制从方法调用返回时,Java虚拟机将尽最大努力从所有丢弃的对象中回收空间。
System.gc()
完全忽略。
似乎没有人提到将对象引用显式设置为null
,这是一种“释放”您可能要考虑的内存的合法技术。
例如,假设您List<String>
在方法开始时就声明了a ,该方法的大小会变得非常大,但只需要在方法进行一半之前就可以了。此时,您可以将List引用设置为,null
以允许垃圾回收器在方法完成之前可能回收该对象(并且无论如何该引用都超出范围)。
请注意,实际上我很少使用这种技术,但是在处理非常大的数据结构时值得考虑。
System.gc();
运行垃圾收集器。
调用gc方法表明,Java虚拟机在回收未使用的对象上花费了很多精力,以使它们当前占用的内存可供快速重用。当控件从方法调用返回时,Java虚拟机将尽最大努力从所有丢弃的对象中回收空间。
不建议。
编辑:我在2009年写了原始回复。现在是2015年。
在Java诞生约20年的时间里,垃圾收集器一直在稳步改善。此时,如果您要手动调用垃圾收集器,则可能需要考虑其他方法:
*“我个人将空变量用作占位符以进行将来的适当删除。例如,在实际删除数组本身(使之为null)之前,我花了一些时间使数组的所有元素无效。”
这是不必要的。Java GC的工作方式是找到没有对其引用的对象,因此,如果我有一个带有引用(=变量)a的对象x指向它,则GC不会删除它,因为有一个引用到该对象:
a -> x
如果您将a设为null,则会发生这种情况:
a -> null
x
因此,x现在没有指向它的引用,它将被删除。当您将a设置为引用与x不同的对象时,会发生相同的事情。
因此,如果您有一个引用对象x,y和z的数组arr和一个引用该数组的变量a,则它看起来像这样:
a -> arr -> x
-> y
-> z
如果您将a设为null,则会发生这种情况:
a -> null
arr -> x
-> y
-> z
因此,GC发现arr没有设置引用,并将其删除,从而为您提供了以下结构:
a -> null
x
y
z
现在,GC将找到x,y和z并将其删除。清空数组中的每个引用不会有任何改善,它只会占用代码中的CPU时间和空间(也就是说,它不会对此造成更大的损害。GC仍然可以执行应有的方式)。
想要从任何程序中释放内存的正确原因(是否为java)是为了使更多内存可用于操作系统级别的其他程序。如果我的Java应用程序正在使用250MB,则可能需要将其降低到1MB,并使249MB可用于其他应用程序。
为了扩展Yiannis Xanthopoulos和Hot Licks的回答和评论(对不起,我还不能发表评论!),您可以像以下示例一样设置VM选项:
-XX:+UseG1GC -XX:MinHeapFreeRatio=15 -XX:MaxHeapFreeRatio=30
在我的jdk 7中,如果在VM空闲后GC后超过30%的堆可用,这将释放未使用的VM内存。您可能需要调整这些参数。
虽然在下面的链接中没有强调它,但是请注意,如果您碰巧具有多个核心,则某些垃圾收集器可能不会遵循这些参数,并且默认情况下,Java可能会为您选择其中一个参数(因此,上面的UseG1GC参数)。
更新:对于Java 1.8.0_73,我已经看到JVM偶尔会使用默认设置释放少量内容。似乎只有在未使用约70%的堆时才这样做。.不知道如果操作系统的物理内存不足,是否会更积极地释放。
我已经对此做了实验。
确实System.gc();
只建议运行垃圾收集器。
但是System.gc();
在将所有引用都设置为后调用null
,将会提高性能和内存占用。
完全来自javacoffeebreak.com/faq/faq0012.html
低优先级的线程会自动为用户处理垃圾回收。在空闲时间期间,线程可能会被调用,并且它可以开始释放以前分配给Java对象的内存。但请放心-它不会删除您的物件!
当没有对对象的引用时,对于垃圾收集器来说,它就变成了公平的游戏。无需调用某些例程(如C ++中的免费例程),只需将对对象的所有引用分配为null,或为该引用分配一个新的类。
范例:
public static void main(String args[]) { // Instantiate a large memory using class MyLargeMemoryUsingClass myClass = new MyLargeMemoryUsingClass(8192); // Do some work for ( .............. ) { // Do some processing on myClass } // Clear reference to myClass myClass = null; // Continue processing, safe in the knowledge // that the garbage collector will reclaim myClass }
如果您的代码将要请求大量内存,则可能需要请求垃圾收集器开始回收空间,而不是允许它作为低优先级线程来这样做。为此,将以下内容添加到您的代码中
System.gc();
垃圾收集器将尝试回收可用空间,并且您的应用程序可以继续执行,并回收尽可能多的内存(内存碎片问题可能适用于某些平台)。
*“例如,假设您在方法的开头声明了一个List,该方法的大小变得非常大,但只需要在方法进行到一半时即可。此时,您可以将List引用设置为null以允许垃圾收集器在方法完成之前可能收回该对象(无论如何引用都超出范围)。” *
这是正确的,但是此解决方案可能无法推广。将List对象引用设置为null时,将使内存可用于垃圾回收,但这仅适用于基本类型的List对象。如果List对象包含引用类型,则将List对象设置为null不会取消引用列表中包含的任何引用类型。在这种情况下,将List object设置为null将孤立包含的引用类型,这些对象的对象不可用于垃圾回收,除非垃圾回收算法足够聪明,可以确定对象已被孤立。
JAVA建议将其分配为null
从https://docs.oracle.com/cd/E19159-01/819-3681/abebi/index.html
为不再需要的变量显式分配空值有助于垃圾回收器识别可以安全回收的内存部分。尽管Java提供了内存管理,但是它不能防止内存泄漏或使用过多的内存。
应用程序可能不释放对象引用而导致内存泄漏。这样做会阻止Java垃圾回收器回收这些对象,并导致使用的内存量增加。使用变量后,显式取消对变量的引用可以使垃圾回收器回收内存。
检测内存泄漏的一种方法是使用性能分析工具,并在每次事务后获取内存快照。处于稳定状态的无泄漏应用程序将在垃圾回收后显示稳定的活动堆内存。