即使很棘手,也可以用Java强制进行垃圾回收吗?我知道System.gc();
,Runtime.gc();
但是他们只建议做GC。我该如何强制GC?
即使很棘手,也可以用Java强制进行垃圾回收吗?我知道System.gc();
,Runtime.gc();
但是他们只建议做GC。我该如何强制GC?
Answers:
最好的选择是调用System.gc()
,这只是向垃圾收集器提示您要它进行收集。由于垃圾收集器是不确定的,因此无法强制立即收集。
non-deterministic == trouble
GC.Collect()
无法收集。在Java gc()
中。
该jlibs库中有垃圾收集一个很好的实用工具类。您可以使用带有WeakReference对象的漂亮技巧来强制进行垃圾收集。
来自jlib的RuntimeUtil.gc():
/**
* This method guarantees that garbage collection is
* done unlike <code>{@link System#gc()}</code>
*/
public static void gc() {
Object obj = new Object();
WeakReference ref = new WeakReference<Object>(obj);
obj = null;
while(ref.get() != null) {
System.gc();
}
}
PhantomReference
与a 配合使用ReferenceQueue
,然后在完成后但仍在清除之前得到通知。最后,即使您成功检测到该对象的内存已被回收,在像HotSpot这样的世代GC中,它的意义仍然很小。通常,它与年轻一代的清理工作相吻合。
System.gc(); System.gc();
,但是确定它是否比它更好地工作肯定很有趣。实际上,只需打印它调用的次数就System.gc()
足够了。达到2的机会很小。
使用Java™虚拟机工具接口(JVM TI),该功能
jvmtiError ForceGarbageCollection(jvmtiEnv* env)
将“强制VM执行垃圾回收。” JVM TI是JavaTM平台调试器体系结构(JPDA)的一部分。
是的,几乎可以强迫您必须以相同的顺序调用方法,并且同时调用这些方法:
System.gc ();
System.runFinalization ();
即使只是一个对象,同时清除这两种方法的使用,也迫使垃圾回收器使用finalise()
无法访问的对象的方法来释放分配的内存并执行该finalize()
方法说明的操作。
但是,使用垃圾收集器是一种可怕的做法,因为使用垃圾收集器可能导致软件过载,甚至比内存还严重,因此垃圾收集器有自己的线程,无法控制,具体取决于gc所使用的算法可能会花费更多时间,并且效率很低,您应该在gc的帮助下检查软件是否最差,因为它肯定已损坏,好的解决方案一定不能依赖gc。
注意:请记住,仅当在finalize方法中不是重新分配对象时,此方法才有效,如果发生这种情况,对象将保持活动并具有技术上可能的复活。
gc()
这只是运行垃圾回收的提示。runFinalizers()
仅对“已被发现丢弃的对象”运行终结器。如果gc并未真正运行,则可能没有此类对象...
根据OutOfMemoryError的文档,它声明除非VM在完全垃圾回收后未能回收内存,否则不会抛出该内存。因此,如果在出现错误之前一直分配内存,那么您将已经强制执行完整的垃圾回收。
大概您真正想问的问题是:“我该如何回收我认为应该通过垃圾回收回收的内存?”
要手动请求GC(而不是从System.gc()):
.gc是将来版本中淘汰的候选人-Sun工程师曾经评论说,全世界可能只有不到二十个人知道如何使用.gc()-昨晚我在中央/关键位置上做了一些工作使用SecureRandom生成的数据的数据结构,在40,000个对象之前,vm会变慢,就像指针用完了一样。显然,它阻塞了16位指针表,并表现出经典的“故障机制”行为。
我尝试了-Xms,依此类推,一直保持旋转状态直到它运行到大约57,xxx。然后,在gc()之后,它将使gc从57,127变为57,128-大约是Easy Money营地的代码膨胀速度。
您的设计需要基本的返工,可能是滑动窗口方法。
您可以从命令行触发GC。这对于批处理/ crontab很有用:
jdk1.7.0/bin/jcmd <pid> GC.run
见:
如果描述需要垃圾收集的原因,那会更好。如果您使用的是SWT,则可以处置诸如Image
和Font
释放内存的资源。例如:
Image img = new Image(Display.getDefault(), 16, 16);
img.dispose();
还有确定未使用资源的工具。
如果您的内存用完了,OutOfMemoryException
可以尝试使用java -Xms128m -Xmx512m
而不是just 来开始编程,从而增加java可用的堆空间量java
。这将使您的初始堆大小为128Mb,最大为512Mb,这远远超过标准的32Mb / 128Mb。
java -Xms512M -Xmx1024M
另一个选择是不创建新对象。
对象池已消失,以减少Java中对GC的需求。
对象池通常不会比对象创建(特别是轻量级对象)要快,但是它比垃圾收集要快。如果创建了10,000个对象,而每个对象为16个字节。必须回收160,000字节的GC。另一方面,如果您不需要同时使用所有10,000个对象,则可以创建一个池来回收/重用这些对象,从而无需构造新对象,也无需使用GC旧对象。
像这样(未经测试)。并且,如果您希望它是线程安全的,则可以将LinkedList换成ConcurrentLinkedQueue。
public abstract class Pool<T> {
private int mApproximateSize;
private LinkedList<T> mPool = new LinkedList<>();
public Pool(int approximateSize) {
mApproximateSize = approximateSize;
}
public T attain() {
T item = mPool.poll();
if (item == null) {
item = newInstance();
}
return item;
}
public void release(T item) {
int approxSize = mPool.size(); // not guaranteed accurate
if (approxSize < mApproximateSize) {
recycle(item);
mPool.add(item);
} else if (approxSize > mApproximateSize) {
decommission(mPool.poll());
}
}
public abstract T newInstance();
public abstract void recycle(T item);
public void decommission(T item) { }
}
真的,我不明白你的意思。但是要弄清楚“无限对象创建”,我的意思是我的大系统上有一些代码可以创建处理并在内存中存活的对象,实际上我无法获得这部分代码,只是手势!
这是正确的,只是手势。您已经有几张海报已经给出的标准答案。让我们一一介绍:
正确,没有实际的jvm-这只是一个规范,一堆描述所需行为的计算机科学...我最近研究了利用本机代码初始化Java对象的方法。为了获得您想要的,唯一的方法是执行所谓的主动空值。如果做错了错误,那是很糟糕的事情,以至于我们不得不将自己限制在问题的原始范围之内:
这里的大多数张贴者都将假设您是在说您正在使用某个界面,如果这样的话,我们必须查看您是一次将整个对象还是一件物品交给了您。
如果不再需要对象,则可以为该对象分配空值,但是如果弄错了该对象,则会生成一个空指针异常。我敢打赌,如果您使用NIO,则可以实现更好的工作
任何时候您或我或任何其他人得到:“ 请我非常需要它。 ”它几乎是您正在努力工作的几乎完全破坏的普遍先兆....给我们写一个小样本代码,对其中的任何内容进行消毒实际使用的代码,并向我们显示您的问题。
不要沮丧。通常,这可以解决的问题是您的dba使用的是在某处购买的软件包,而原始设计并未针对海量数据结构进行调整。
这是很常见的。
费耶
方法调用System.runFinalizersOnExit(true)保证在Java关闭之前调用终结器方法。但是,此方法本质上是不安全的,已被弃用。一种替代方法是使用Runtime.addShutdownHook方法添加“关闭挂钩”。
马萨拉特·西迪基(Masarrat Siddiqui)
有一些强制垃圾回收器的间接方法。您只需要用临时对象填充堆,直到执行垃圾收集器为止。我已经制作了以这种方式强制垃圾收集器的类:
class GarbageCollectorManager {
private static boolean collectionWasForced;
private static int refCounter = 0;
public GarbageCollectorManager() {
refCounter++;
}
@Override
protected void finalize() {
try {
collectionWasForced = true;
refCounter--;
super.finalize();
} catch (Throwable ex) {
Logger.getLogger(GarbageCollectorManager.class.getName()).log(Level.SEVERE, null, ex);
}
}
public int forceGarbageCollection() {
final int TEMPORARY_ARRAY_SIZE_FOR_GC = 200_000;
int iterationsUntilCollected = 0;
collectionWasForced = false;
if (refCounter < 2)
new GarbageCollectorManager();
while (!collectionWasForced) {
iterationsUntilCollected++;
int[] arr = new int[TEMPORARY_ARRAY_SIZE_FOR_GC];
arr = null;
}
return iterationsUntilCollected;
}
}
用法:
GarbageCollectorManager manager = new GarbageCollectorManager();
int iterationsUntilGcExecuted = manager.forceGarbageCollection();
我不知道这种方法有多少用处,因为它会不断填充堆,但是如果您有必须强制使用GC的关键任务应用程序-这可能是Java便携式方法来强制使用GC。
我想在这里添加一些东西。请不要让Java在虚拟机而不是实际的机器上运行。虚拟机具有自己的与计算机通信的方式。它可能因系统而异。现在,当我们调用GC时,我们要求Java虚拟机调用垃圾收集器。
由于Garbage Collector随虚拟机一起使用,我们不能强迫它在那里进行清理。而是我们将请求与垃圾收集器排队。它取决于虚拟机,在特定时间(这可能会因系统而异,通常在分配给JVM的阈值内存已满时)之后,实际计算机将释放空间。:D
以下代码来自assertGC(...)方法。它试图强制非确定性垃圾收集器进行收集。
List<byte[]> alloc = new ArrayList<byte[]>();
int size = 100000;
for (int i = 0; i < 50; i++) {
if (ref.get() == null) {
// Test succeeded! Week referenced object has been cleared by gc.
return;
}
try {
System.gc();
} catch (OutOfMemoryError error) {
// OK
}
try {
System.runFinalization();
} catch (OutOfMemoryError error) {
// OK
}
// Approach the jvm maximal allocatable memory threshold
try {
// Allocates memory.
alloc.add(new byte[size]);
// The amount of allocated memory is increased for the next iteration.
size = (int)(((double)size) * 1.3);
} catch (OutOfMemoryError error) {
// The amount of allocated memory is decreased for the next iteration.
size = size / 2;
}
try {
if (i % 3 == 0) Thread.sleep(321);
} catch (InterruptedException t) {
// ignore
}
}
// Test failed!
// Free resources required for testing
alloc = null;
// Try to find out who holds the reference.
String str = null;
try {
str = findRefsFromRoot(ref.get(), rootsHint);
} catch (Exception e) {
throw new AssertionFailedErrorException(e);
} catch (OutOfMemoryError err) {
// OK
}
fail(text + ":\n" + str);
来源(为清楚起见,我添加了一些评论):NbTestCase示例