你的位置:首页 > Java教程

[Java教程]使用jprofile发现和修复内存泄露


性能分析有一项是:发生OOM时,浏览对象分配和引用以发现和修复内存泄露;

示例程序PointFactory

public class PointFactory {  protected ArrayList points = new ArrayList();  protected static PointFactory instance = new PointFactory();  public Point createPoint(int x, int y) {    Point point = new Point(x, y);    this.points.add(point);    return point;  }  public void removePoint(Point point) {    this.points.remove(point);  }  public void printTestPoints() {    for (int i = 0; i < 5; i++) {      Point point = createPoint(i, i);      System.out.println("Point = " + point);    }  }  public static PointFactory getInstance() {    return instance;  }  public static void main(String[] args) throws Exception {    JFrame frame = new JFrame("Points Test");    frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);    JButton button = new JButton("Print Test Points");    button.addActionListener(new ActionListener() {      public void actionPerformed(ActionEvent e) {        PointFactory.getInstance().printTestPoints();      }    });    frame.getContentPane().add(button);    frame.setSize(200, 100);    frame.setVisible(true);  }}

View Code

 

运行PointFactory;

clip_image001[8]

运行jprofile,选择本地jvm;

clip_image002[5]

选择程序;

clip_image003[4]

来了个很恐怖的警告:

clip_image004[4]

某些情况下,在attach mode下有一个bug会导致jvm崩溃;

Sun JVM Attach API是Sun JVM中的一套非标准的可以连接到JVM上的API;

Bug详情:

  • Sun Java (HotSpot) client JVM can crash in attach mode due to a JVM bug
    Due to a JVM bug 6776659 HotSpot client JVM can crash in attach mode.
    There is no crash for the server JVM: JVM option -server solves the problem.

源文档 <https://www.yourkit.com/docs/java/help/attach_agent.jsp>

咱还是听话运行在server mode吧;

clip_image005[4]

这次就没提示了;

选择

clip_image006[4]

选择instrumentation仪表盘,我们要看所有的分析;

clip_image007[4]

这么多类咋看嘛,怀疑Point类存在内存泄露,那就只看它了,设置View Filters;

clip_image008[4]

这时候还没有点按钮,所以没有创建一个类;点!

clip_image009[4]

clip_image010[4]

但是视图里边还是空啊;

得用java.awt.Point,幸好我够机智;

clip_image011[4]

为啥5个类出来total是333?

再点一次,变成418;

clip_image012[4]

点击垃圾回收Run GC:

clip_image013[4]

剩10个实例,正常了;本应10个实例,为什么会有418个那么多;

以此类推,点按钮,Run GC,然后total每点一次增加5个,证明了Point类是回收不掉的;

已经集成到eclipse的话,可以Profile As Java application,很方便;

clip_image014[4]

那为啥Point类没释放呢?明明它已经没用了;

实际项目中,找源代码然后逐个找引用会累死人,咱还是通过运行时堆栈的快照来看吧;

切换到Heap视图;

clip_image015[6]

在累计引用列表可以看到谁引用了Point;

clip_image015[7]

这里是points这个Arraylist引用了,但是没有移除导致;

使用完之后调用removePoint就可以了。