内存分析篇
VisualVM 通过检测 JVM 中加载的类和对象信息等帮助我们分析内存使用情况,我们可以通过 VisualVM 的监视标签对应用程序进行内存分析。
一.内存堆Heap
首先我们来看内存堆Heap使用情况,我本机eclipse的进程在visualVM显示如下:
随便写个小程序占用内存大的,运行一下
程序如下:
package jvisualVM; public class JavaHeapTest { public final static int OUTOFMEMORY = 200000000; private String oom; private int length; StringBuffer tempOOM = new StringBuffer(); public JavaHeapTest(int leng) { this.length = leng; int i = 0; while (i < leng) { i++; try { tempOOM.append("a"); } catch (OutOfMemoryError e) { e.printStackTrace(); break; } } this.oom = tempOOM.toString(); } public String getOom() { return oom; } public int getLength() { return length; } public static void main(String[] args) { JavaHeapTest javaHeapTest = new JavaHeapTest(OUTOFMEMORY); System.out.println(javaHeapTest.getOom().length()); } }
查看VisualVM Monitor tab, 堆内存变大了
在程序运行结束之前, 点击Heap Dump 按钮, 等待一会儿,得到dump结果,可以看到一些Summary信息
点击Classes, 发现char[]所占用的内存是最大的
双击它,得到如下Instances结果
Instances是按Size由大到小排列的
第一个就是最大的, 展开Field区域的 values
StringBuffer类型的 全局变量 tempOOM 占用内存特别大, 注意局部变量是无法通过 堆dump来得到分析结果的。
另外,对于“堆 dump”来说,在远程监控jvm的时候,VisualVM是没有这个功能的,只有本地监控的时候才有。
二.永久保留区域PermGen
其次来看下永久保留区域PermGen使用情况
运行一段类加载的程序,代码如下:
package jvisualVM; import java.io.File; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.List; public class TestPermGen { private static List<Object> insList = new ArrayList<Object>(); public static void main(String[] args) throws Exception { permLeak(); } private static void permLeak() throws Exception { for (int i = 0; i < 1000; i++) { URL[] urls = getURLS(); URLClassLoader urlClassloader = new URLClassLoader(urls, null); Class<?> logfClass = Class.forName("org.apache.commons.logging.LogFactory", true,urlClassloader); Method getLog = logfClass.getMethod("getLog", String.class); Object result = getLog.invoke(logfClass, "TestPermGen"); insList.add(result); System.out.println(i + ": " + result); } } private static URL[] getURLS() throws MalformedURLException { File libDir = new File("C:/Users/wadexu/.m2/repository/commons-logging/commons-logging/1.1.1"); File[] subFiles = libDir.listFiles(); int count = subFiles.length; URL[] urls = new URL[count]; for (int i = 0; i < count; i++) { urls[i] = subFiles[i].toURI().toURL(); } return urls; } }
一个类型装载之后会创建一个对应的java.lang.Class实例,这个实例本身和普通对象实例一样存储于堆中,我觉得之所以说是这是一种特殊的实例,某种程度上是因为其充当了访问PermGen区域中类型信息的代理者。
运行一段时间后抛OutOfMemoryError了, VisualVM监控结果如下:
结论:PermGen区域分配的堆空间过小,我们可以通过设置-XX: PermSize参数和-XX:MaxPermSize参数来解决。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix