性能分析有一项是:发生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); } }
运行PointFactory;
运行jprofile,选择本地jvm;
选择程序;
来了个很恐怖的警告:
某些情况下,在attach mode下有一个bug会导致jvm崩溃;
Sun JVM Attach API是Sun JVM中的一套非标准的可以连接到JVM上的API;
Bug详情:
源文档 <https://www.yourkit.com/docs/java/help/attach_agent.jsp>
咱还是听话运行在server mode吧;
这次就没提示了;
选择
选择instrumentation仪表盘,我们要看所有的分析;
这么多类咋看嘛,怀疑Point类存在内存泄露,那就只看它了,设置View Filters;
这时候还没有点按钮,所以没有创建一个类;点!
但是视图里边还是空啊;
得用java.awt.Point,幸好我够机智;
为啥5个类出来total是333?
再点一次,变成418;
点击垃圾回收Run GC:
剩10个实例,正常了;本应10个实例,为什么会有418个那么多;
以此类推,点按钮,Run GC,然后total每点一次增加5个,证明了Point类是回收不掉的;
已经集成到eclipse的话,可以Profile As Java application,很方便;
那为啥Point类没释放呢?明明它已经没用了;
实际项目中,找源代码然后逐个找引用会累死人,咱还是通过运行时堆栈的快照来看吧;
切换到Heap视图;
在累计引用列表可以看到谁引用了Point;
这里是points这个Arraylist引用了,但是没有移除导致;
使用完之后调用removePoint就可以了。