【问题标题】:When does the perm gen get collected?perm gen什么时候收集?
【发布时间】:2011-11-05 00:15:22
【问题描述】:

我在使用 CMS 收集器和内存条来触发 GC 的 Tomcat 应用程序上工作。当我重新加载 webapps 时,我有时会遇到这样的情况,即老一代已满足以触发 GC,但没有收集到死掉的类加载器。

我读到类被分配到 perm gen 中,并猜测它们因此被 Old gen 集合忽略了。我编写了以下测试类来测试这个理论。

package test;

import java.io.IOException;
import java.io.InputStream;

import org.apache.commons.io.IOUtils;

/*
 JVM Options:
 -server -XX:+UseMembar -XX:+UseConcMarkSweepGC
 -XX:+UseParNewGC -XX:CMSInitiatingOccupancyFraction=80
 -XX:+UseCMSInitiatingOccupancyOnly -Xms100m -Xmx100m
 -XX:PermSize=100m -XX:NewSize=10m -XX:MaxNewSize=10m
 -verbose:gc -Xloggc:gc.log  -XX:+PrintGCTimeStamps
 -XX:+PrintGCDetails
 */
public class ClassLoaderTest extends ClassLoader
{
  @Override
  protected synchronized Class<?> loadClass(String xiName, boolean xiResolve)
      throws ClassNotFoundException
  {
    if (xiName.equals("test"))
    {
      // When asked to load "test", load Example.class
      Class<?> c = Example.class;
      String className = c.getName();
      String classAsPath = className.replace('.', '/') + ".class";
      InputStream stream = c.getClassLoader().getResourceAsStream(classAsPath);
      byte[] classData = null;
      try
      {
        classData = IOUtils.toByteArray(stream);
      }
      catch (IOException e)
      {
        e.printStackTrace();
      }
      return defineClass(className, classData, 0, classData.length);
    }
    return super.loadClass(xiName, xiResolve);
  }

  public static class Example {}
  public static ClassLoaderTest classLoaderTest;

  public static void main(String[] args) throws Exception
  {
    // Allocate CL in new gen
    classLoaderTest = new ClassLoaderTest();

    // Load a class - allocated in perm gen
    classLoaderTest.loadClass("test");

    // Discard CL
    classLoaderTest = null;

    // Pause at end
    Thread.sleep(99 * 60 * 1000);
  }

  public final byte[] mMem = new byte[85 * 1024 * 1024];
}

我运行这个类并使用 VisualVM 监视输出,发现确实发生了多个 Old 和 Young gen 集合,而没有收集到死的 Classloader,因此大字节数组保留在内存中。

什么会触发 Perm Gen 被收集?

【问题讨论】:

  • 你知道“Perm”是...right?的缩写
  • Java Perm Gen 中分配的内存仍然可以被收集。 JVM 使用 Perm Gen 来保存它期望很少被释放的数据。

标签: java class garbage-collection permgen


【解决方案1】:

查看 JVM 选项“CMSPermGenSweepingEnabled”和“CMSClassUnloadingEnabled”。 (网上有很多关于它们使用的讨论。)特别是,第一个假设将 PermGen 包含在垃圾收集运行中。默认情况下,PermGen 空间永远不会包含在垃圾回收中(因此会无限增长)。

【讨论】:

  • 它不会无限增长,有一个非常明确的上限。这就是为什么你经常遇到可怕的类加载器泄漏:blogs.oracle.com/fkieviet/entry/…
  • @Cameron Skinner +点了!它尝试增长而不考虑 MaxPermSize :-)
  • 我尝试将 -XX:+CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabled 添加到我的 JVM 参数中。我发现只有 -XX:+CMSClassUnloadingEnabled 实际上做了任何事情。我还惊讶地发现,在第二次年轻代收集后不久,2 分钟后才收集了烫发代。
  • 这些选项的效果将取决于 JVM 版本。谢谢分享,mchr!
  • 在我的本地开发机器上,我运行 1.6.0_24。我刚刚在我的服务器上重新测试,由于各种原因卡在 1.6.0_07 上。 -XX:+CMSClassUnloadingEnabled 适用于两个版本。
猜你喜欢
  • 2013-05-15
  • 2014-03-12
  • 1970-01-01
  • 1970-01-01
  • 2016-09-10
  • 2015-03-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多