【问题标题】:How to track any object creation in Java since freeMemory() only reports long-lived objects?由于 freeMemory() 只报告长期存在的对象,如何跟踪 Java 中的任何对象创建?
【发布时间】:2012-03-21 17:58:44
【问题描述】:

每当我的 JVM 创建一个新对象时,我都想在日志中打印一些内容。我试图使用 Runtime.getRuntime().freeMemory() 检测到这一点,但不幸的是,在将其提升到堆 (check here for more details) 之前,它不会考虑任何短期对象。

那么有谁知道我的 JVM 实例化/创建对象时如何检测/跟踪?为方便起见,我们如何完成下面的代码:

随意使用 MemoryPoolMXBean 和 JMX:

public class MemoryUtils {

    private static Set<String> set = new HashSet<String>();

    public static void main(String[] args) {

        // START

        // now create a bunch of objects and save them in the set
        for (int i = 0; i < 100; i++) {
            set.add(new String("foo" + i));
        }

        // FINISH

        // FIXME: Do something here to detect that a bunch of objects were created!

    }
}

编辑:以下弗拉基米尔提出的尝试解决方案:

它有效,但有一个奇怪的副作用:

long t = totalThreadMemoryAllocated();

// did nothing

t = totalThreadMemoryAllocated() - t;

System.out.println(t); // ==> 48 !!!???

public static long totalThreadMemoryAllocated() {
    com.sun.management.ThreadMXBean tBean = (com.sun.management.ThreadMXBean) ManagementFactory.getThreadMXBean();
    return tBean.getThreadAllocatedBytes(Thread.currentThread().getId());
}

但它确实说明了任何对象的创建,所以我想如果我从中减去幻数 48 就可以使用它。

【问题讨论】:

  • 是否可以选择使用 AspectJ?如果是这样,这个问题可能包含可以修改的代码,以便在任何构造函数调用时触发方面:stackoverflow.com/questions/6402304/help-with-pointcut-aspectj
  • 感谢@Joe23,但我正在寻找更纯粹的 java 解决方案。我认为使用 JMX 访问所有内存池并添加使用的内存可能是解决方案,所以当我的总增加时,我可以假设我在某处创建了对象(也假设 GC 没有触发)
  • 我认为您对 Java 堆的工作原理了解不足。在(缓慢的)调试环境之外,没有办法做你想做的事。
  • @Hot Licks 没有什么是不可能的。检查弗拉基米尔的答案!
  • 啊,但是知道分配了多少字节几乎没用。

标签: java optimization garbage-collection jmx


【解决方案1】:

您可以使用 Java 代理来执行此操作,可以通过作者的博客找到开源实现 - http://jeremymanson.blogspot.co.uk/2012/02/update-to-allocation-instrumenter.html

【讨论】:

    【解决方案2】:

    Sun JVM(1.6.0u26 及更高版本)具有ThreadMXBean#getThreadAllocatedBytes 方法,用于报告线程分配的总字节数。 这不会区分活动/死内存,但是这将允许您检测内存分配并测量这些分配的总量。

    要使用这种方法,您只需查找常规 ThreadMXBean,然后将其转换为 com.sun.management.ThreadMXBean 或使用反射来调用该方法。

    【讨论】:

    • 请看我上面的编辑。即使我什么都不做,它也会报告 48。我尝试了任何东西,但分配任何东西的不是 Thread.currentThread。我认为对 getThreadAllocatedBytes 的调用本身会以某种方式创建 48 个字节。
    • 据我了解,这 48 个字节来自两个 long[1] 数组:docjar.com/html/api/sun/management/ThreadImpl.java.html#321
    • @chrisapotek:如果我理解正确,你运行 32 位 JVM,所以每个数组消耗 8(header)+4(length)+8(1 item -- long)+4(padding for 8字节对齐)=24 字节。如果您在 64 位 JVM 中测试 getThreadAllocatedBytes,那么 magic 48 会变成 2 arrays*(16+4+8+4) = "magic 64"
    • 我试图避免创建内存以及告诉我创建内存的方法。 :) 并且没有转义,因为其中一个长数组是使用本机代码创建的。 :(
    【解决方案3】:

    我编写了一个开源工具来跟踪对象分配和对象生命周期:http://mchr3k.github.com/org.inmemprofiler/

    我的工具不会让您将所有对象分配记录到自己的日志中,但会在您希望主动追踪对象泄漏或过多对象分配等事情的假设下执行自己的分析。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-23
      • 2011-11-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多