1)内存结构
堆 | Young新生代 | Eden(伊甸) |
|
Survivor(幸存者) | from区和to区,严格一致 | ||
Tenure老生代 |
| ||
非堆 | 栈 | 线程栈 | 线程私有,基本的数据类型和引用,方法出口后进先出 数据可共享,如a=3;b=3;指向同一个 |
本地方法栈 | 为调用Native方法服务 | ||
程序计数器 | 线程私有,程序执行的位置 | ||
永久代PermGen space | 方法区 | 线程共享,类信息,运行时常量池 (编译期生成的字面量和符号。String intern方法) | |
静态域 | static静态成员 | ||
直接内存 | NIO中用native函数分配堆外内存,通过DirectByteBuffer来引用,避免java堆和Native堆的来回复制 |
周期:Eden-Survivor-Tenure,from to 复制
new出的对象?new对象里的引用在哪?应该是堆里对象中要存储一份引用,栈里也要存一份。
2)dump内存
如果要查内存泄露,必须先dump出JVM 的heap:
/usr/java/bin/jmap -dump:file=hprof-jvm.bin -F PID (进程号)
dump到文件以后下载到本地,用工具查看,工具会给你列出最耗内存的地方,然后你可以根据内存的变化来判断这些代码存在内存泄露的可能性。
Eclipse Memory Analysis Eclipse 插件在线安装地址:http://download.eclipse.org/mat/1.0/update-site/
<!--[if !supportLists]-->1. <!--[endif]-->在histogram的filter中输入.*类名.*来查找类要监控的类信息。
<!--[if !supportLists]-->2. <!--[endif]--> List objects -> with incoming references
<!--[if !supportLists]-->3. <!--[endif]--> Path To GC Roots -> exclude weak/soft references, 过滤掉弱引用
system class loader在没有指定装载器的情况下默认装载用户类,在Sun Java 1.5中既sun.misc.Launcher$AppClassLoader
shallowHeap对象自身占用的内存大小,不包括它引用的对象 RetainedHeap
树形是对象的引用链条不是方法调用链条
在崩溃之前dump: -XX:+HeapDumpOnOutOfMemoryError
3)垃圾回收
垃圾判断
引用计数 | 当有引用连接对象时计数加1,引用离开作用域或置为null时引用减去1,开销在整个生命周期,要处理循环引用,基本不采用 |
根搜索法 | 从堆栈和静态存储区开始,遍历所有的引用 |
回收垃圾
标记-清除 | 一轮标记哪些需要清除,一轮进行清除(如果对象比较稳定,回收器会自动切换到标记-清除模式) |
停止-复制 | 先暂停程序的运行,把活着的对象从当前堆拷贝到另一个堆,没有复制的全是垃圾 位于堆或静态存储区的引用可以直接直接被修正 |
4)GC调优
两个指标是吞吐率(除去垃圾回收所用时间占总时间的百分比)和停顿时间(垃圾回收需要停顿应用的时间)
-XX:MaxGCPauseMillis=5000 | GC最大停顿时间,尽力保持在指定毫秒以内, 如果无法满足,则相应的内存区会缩小,以缩短GC的停顿时间。 |
-XX:GCTimeRatio=19 | 1/(1+19)=1/20=5%默认值为99,即GC时间占总的应用运行时间为1%。如果无法满足,相应的内存区会扩大,以提高应用在两次GC间的运行时间 |
-Xms2048 -Xmx2048 | 表示jvm堆内存大小,以及最大堆内存大小。一般设为同样大小 |
-Xmn768m | 是将NewSize与MaxNewSize设为一致。表示新生代初始内存大小,以及最大新生代内存大小。一般情况下建议设置为总堆内存的3/8。 |
-XX:PermSize=512m -XX:MaxPermSize=512m | 设置永久区初始内存以及最大内存。建议设置为同样大小 |
-XX:NewRato=3 | NewSize(-Xmn)已设置,此项可不设。young(新生代) 和 tenured(老生代)的比例是1:3 |