【问题标题】:How to find how many strong references for a object in heap/stack at runtime如何在运行时查找堆/堆栈中对象的强引用数
【发布时间】:2012-09-13 18:52:08
【问题描述】:

团队,

在 java 中是否有可能知道当前可用的对象有多少活动/强引用?

例如在下面的代码中; A 类的对象可以被项目中的许多类持有。但我想在监视器线程中打印它。

public class A {
  public static A a = new A();
  public static A getInstance() {
     return a;
  }

  private A() {
     new Monitor(this).start();
  }


  class Monitor extends Thread {
      A refA;
      public Monitor(A ref) {
         this.refA = ref;
      }
      public void run () {

      //TODO Print how many references currently available for Object A referenced by refA;
      //Sure It will be minimum one. (which is "a" in this class A)   
      } 

   }
}

请不要太重视这个示例程序。我的问题是如何找到堆/堆栈中对象可用的强引用数量?唯一的好处是我们为该对象提供了一个强有力的参考。

如果在 java 中是不可能的;我可以通过这个对 C 语言的强引用吗?从 C 语言中我可以做到这一点吗?

我只是想知道探查器/工具是如何做到这一点的? 请帮忙。

【问题讨论】:

  • 我想在调用 getInstance() 后只有一个活动引用时执行一些操作。表示 getInstance() 的调用方方法在堆栈中结束。所以我们只有一个活跃的引用,即“a”。
  • 看起来你需要某种 Aspect 能力,试试 AspectJ 或 Spring AOP。
  • 您只需要“向上”侧翼还是两者都需要?我的意思是你需要做一些事情1)当计数从0变为1时,2)每次计数从0变为1,3)每次计数从X!= 1变为1?跨度>

标签: java c garbage-collection heap-memory


【解决方案1】:

不,如果不更改 VM 上的类或分支工具,您将无法获得准确的计数(由于对性能的影响,这很难在生产中进行)。

使用the ref package,如果一个对象即将被丢弃(并在此时采取行动)但没有可用的计数(并且并不总是由 VM 处理),您可以收到通知。

【讨论】:

  • 很好。你能告诉我分析器/工具是如何做到的吗? C语言可以吗?那我可以使用本地调用吗?
  • 这样做会严重影响性能,因为现代 JVM 甚至不记录实例数。
  • 谢谢。您能否就我与 Peter Lawrey 的转变提供任何建议?
【解决方案2】:

您可以执行堆转储并对其进行分析以查找对任何对象的引用数。

您对此有什么要求以及您将如何处理这些信息,因为我怀疑有一种更简单/更好的方法可以实现您想要的。


基于WeakHashMap

/**
 * Reference queue for cleared WeakEntries
 */
private final ReferenceQueue<Connection> queue = new ReferenceQueue<>();

List<WeakReference<Connection>> usedConnections = ....

// when you have a new connection

Connection connection = ....
usedConnections.add(new WeakReference(connection, queue));

// checking the queue for discarded objects.

    // remove null references from usedConnections

    for (Connection x; (x = queue.poll()) != null; ) {
        synchronized (queue) {
           x.close();
        }
     }

【讨论】:

  • 从池中请求的代码数据库连接对象中约有 700 个位置;但他们从未关闭。由于 max_no_connection_size 为 75,因此看不到这一点。仅在负载测试期间发现。我只想要解决方案,而不是对所有文件进行代码更改;我怎样才能关闭它池边本身?
  • 听起来你有内存泄漏。我会使用内存分析器来查看它们被保留的位置。您是否关闭了 PreparedStatements 等 JDBC 资源?
  • 该代码从未关闭连接,即使是一个地方。所以现在很难改变到所有这700个地方。那么有什么建议我可以纠正这个吗?
  • 可以通过不使用连接清理资源来保持连接打开。真正的修复是修复代码。任何解决方法都不太可能像您认为的那样起作用,因为仅仅关闭连接是不够的。
  • 语句和结果集在所有这些地方都正确关闭。但是连接没有关闭或没有返回到池中。一件事我可以说一旦事务块结束但没有被释放,引用可能会结束。因此,在 GC 之前,我从 max conn 达到的池中获得了异常。因此,如果没有对此 conn 对象的活动引用,我想这样做,然后通过监视线程关闭/返回池。但是怎么……??? :(
【解决方案3】:

你可以试试这样的东西

Class A
{
   static int instanceCount = 0;
   public A()
   {
      instanceCount++;
   }

   protected finalize()
   {
      instanceCount--;
   }

   public static int getInstanceCount()
   {
       return instanceCount;
   }
}

我相信这是最接近使用代码对类进行引用的方法。希望对您有所帮助...

【讨论】:

  • 希望您知道,一旦 getInstance() 调用者方法代码块结束,引用就会结束。它永远不会与运行时调用的 getInstance() 的数量相同。我们也无法从 finalize() 中获得帮助,因为我们正在讨论活动对象的引用。
  • 在上面的示例中,一个 ClassLoader 的实例计数始终为 1。现在在 JVM 中,即使是由不同 Classloader 加载的相同类也被视为不同的类。因此,在您的情况下,实例数 = 加载类 A 的类加载器数。
猜你喜欢
  • 2011-11-24
  • 2011-01-16
  • 2023-03-03
  • 2016-03-05
  • 2012-05-29
  • 1970-01-01
  • 2014-10-23
  • 2018-09-02
  • 2013-06-26
相关资源
最近更新 更多