- 浏览: 415618 次
- 性别:
- 来自: 深圳
文章分类
最新评论
-
Glogo:
楼主您好,我在试验您的代码的时候发现新开的三个子线程并没有一直 ...
java 高并发 ReentrantLock -- 可重入的锁 -
univasity:
最近发觉也被限速了,投诉一下就好一会~~ 看来明天又要和电信M ...
ADSL上网速度慢 都是帐号限速惹的祸 -
liuyuanhui0301:
java 高并发 ReentrantLock -- 可重入的锁 -
dang_java:
呵.很好的说明文档.
JXTA技术与应用发展 -
helloqidi:
谢谢,学习了
SQL中exists和in的区别
版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
http://fallenlord.blogbus.com/logs/57543373.html
众所周知,Java从1.2开始引入分带GC策略,JVM内存被分成了3个带:young generate、tenured generation和permanent generation
前面两个带相信大家已经非常熟悉了,一般我们所说的GC主要是在这两个带里面运作,我们这里主要讨论Permanent Generation
Perm带是存储类元数据信息的地方,一直以来大家都认为是不会被GC的——确实,类元数据信息被回收了别的类怎么玩?
要说明这个问题,主要需要弄清楚Perm带除了元数据信息外还存了些什么?
栈存基本类型和引用、堆存对象,这个简单的道理大家都懂,但真的是所有的基本类型都存在栈里吗?不见得
还是那句话——无码无真相,我们先从最简单的例子来看一个问题,下面这段代码相信大家都看过很多遍了:
@Test
public void literal() {
String a = "abc";
String b = "abc";
Assert.assertTrue(a == b);
}
没啥好说的,字符串字面量在编译期就会被编译器直接植入.class文件常量池中,并在运行期被JVM当做常量加载,所有存储超过一个字节大小的基本类型都会被编译器优化成这样,这点用javap反编译看下汇编如何压栈的就知道了。关键问题是,常量池在运行期是放在堆里的还是放在栈里的?——答案是都不在
JVM Spec中的Runtime Data Area分为5个区域:pc register、java stack、native stack、java heap、method area,前三个和大多数语言类似比较容易理解,java Heap就是我们常说的堆了,也是Young Generation和Tenured Generation所在,而Method Area就是我们所说的Permanent Generation,上面代码中的字面字符串常量就存在了这里(也有人认为PermGen属于广义上的Heap)
不信?OK,看看下面的代码:
@Test
public void permGenOOM() {
List<String> list = new ArrayList<String>();
for (int i = 0; i < Integer.MAX_VALUE; i++) {
String t = String.valueOf(i).intern();
list.add(t);
}
}
运行前先设置下JVM参数:-XX:PermSize=2M -XX:MaxPermSize=4M,将PermSize调小点,这样比较容易出结果
执行一下,PermGen应该很快就爆了
这里用到了String的intern方法,作用我就不多说了,如果不了解的可以自己看看JDK API,大致就是将一个字符串变量转存到常量区的String Pool中,和直接写字面常量是一样的效果,以下代码可以证明:
@Test
public void literalAndIntern() {
String a = "abc";
String b = new String("abc");
Assert.assertFalse(a == b);
Assert.assertTrue(a == b.intern());
}
OK,既然知道了Permanent Generation中还存着这个东东,那么我们就可以试验GC了
去掉上一段代码的第3和第6行,也就是整个程序不再持有创建出来的intern对象的引用,使得对象可以被GC,同事在JVM参数中追加GC观察-verbose:gc -XX:+PrintGCDetails
@Test
public void permGenGC() {
for (int i = 0; i < Integer.MAX_VALUE; i++) {
String t = String.valueOf(i).intern();
}
}
运行代码,这次是不是没有PermGen OOM了?观察Console中的GC日志,看到很多minor GC,我们主要关注Major GC(Full GC)的内容:
[Full GC [Tenured: 340K->340K(4096K), 0.0197170 secs] 959K->340K(5056K), [Perm : 4096K->799K(4096K)], 0.0199235 secs] [Times: user=0.03 sys=0.00, real=0.03 secs]
看到Perm段,显示PermGen总大小为4096K,此次full gc将其从4096K清理到了799K
到这里应该已经大功告成了,这篇帖子的主题也达到了——GC会清理PermGen
但事情还不算完,既然GC会去动PermGen,那是否会清理类元数据信息呢?虽然看起来很荒谬的理论,但是还是值得尝试一下的:
@Test
public void permGenCglibOOM() {
for (int i = 0; i < Integer.MAX_VALUE; i++) {
createInstance();
}
}
private static ValueObject createInstance() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(ValueObject.class);
enhancer.setUseCache(false); // 关闭CGLib缓存,否则总是生成同一个类
enhancer.setCallback(new MethodInterceptor() {
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy)
throws Throwable {
return proxy.invokeSuper(obj, args);
}
});
return (ValueObject) enhancer.create();
}
public static class ValueObject {
private String username = "guolin";
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
这里我们仿造Hibernate用CGLib动态构造了一堆ValueObject的子类,如愿以偿,很快PermGen就OOM了,观察Full GC日志,PermGen一点都没压下去
[Full GC [Tenured: 1950K->1560K(4096K), 0.0323010 secs] 2637K->1560K(5056K), [Perm : 4095K->4095K(4096K)], 0.0323519 secs] [Times: user=0.03 sys=0.00, real=0.03 secs]
打开Yourkit Memory 一栏,看到 loaded classes and unloaded classes. 既然有unloaded classes, which means the classes can be unloaded.
来分析一下原因,我们生成的classes,是否是因为被引用才不会full gc 回收?
确实有Classloader,这里是系统自带的application class loader,他会hold住所有的class Object 引用。我们尝试用自己的classloader试试。
ClassLoader cl = null;
for(int i = 0; i < Integer.MAX_VALUE; i++)
{
Enhancer enhancer = new Enhancer();
if(i%100 == 0)
{
cl = null;
cl = new MyClassLoader();
}
enhancer.setClassLoader(cl);
enhancer.setUseCache(false);
enhancer.setCallbackType(MyMethodInterceptor.class);
enhancer.createClass();
}
[Full GC [Tenured[Unloading class net.sf.cglib.empty.Object$$EnhancerByCGLIB$$62f811b3_63]
.......
[Unloading class net.sf.cglib.empty.Object$$EnhancerByCGLIB$$62f811b3_38]
: 1025K->866K(2504K), 0.0152307 secs] 1104K->866K(3080K), [Perm : 4095K->2677K(4096K)], 0.0155104 secs]
这次Full GC的时候有unload classes.
So let me sum up when a class is qulified to be unloaded.
- they will not be unloaded while any instances are still in
existence (have not been GC-ed).
- they will not be unloaded while their owning classloader is still in
instances is still in existence (has not been GC-ed).
- they will not be unloaded while their java.lang.Class object is still
referenced from anywhere (same goes for reflective access to their
members).
发表评论
-
JVM 深入笔记
2012-04-12 20:36 916JVM 深入笔记(1)内存区域是如何划分的? 一个超短的前言 ... -
JVM启动参数
2011-06-10 16:27 938java [jvmargs] class [arguments ... -
JVM指令集 和 一个异常例子
2011-05-19 16:14 986指令码 助记符 说明 0x00 nop ... -
The Top Java Memory Problems – Part 1
2011-05-18 11:01 870转载:http://blog.dynatrace.com/20 ... -
BTrace使用简介
2011-04-19 13:51 755该文转载自:http://rdc.taobao.com/tea ... -
大方法的执行性能与调优过程小记
2011-04-18 16:20 766该文章转载自:http://rdc.taobao.com/te ... -
十个最好的Java性能故障排除工具
2011-04-18 16:02 891推荐十个最好的Java性能 ... -
两个OOM Cases排查过程的分享
2011-04-18 15:39 898分享一下两个OOM Cases的查找过程,一个应用是Nativ ... -
Monitoring Java garbage collection with jstat
2011-04-18 15:28 834The original article is at : ht ... -
理解Heap Profling名词-Shallow和Retained Sizes
2011-04-18 14:58 947所有包含Heap Profling功能的工具(MAT, You ... -
Java深度历险(四)——Java垃圾回收机制与引用类型
2011-04-01 08:18 930Java语言的一个重要特性 ... -
Thread Dump 和Java应用诊断
2011-03-30 08:08 1102Thread Dump 和Java应用诊断 ... -
Memory Analysis Part 1 – Obtaining a Java Heapdump
2011-03-14 16:06 1090For troubleshooting Java memory ... -
Java Memory Leaks et al. (2. Act)
2011-03-14 15:37 900The first act of this blog-seri ... -
Erlang memory architecture vs Java memory architecture
2011-03-14 15:36 884I read a really, really interes ... -
The Java Memory Architecture (1. Act)
2011-03-14 15:15 1388One of the biggest strength of ... -
JVM内存模型以及垃圾回收
2011-03-13 09:38 914内存由 Perm 和 Heap 组成. 其中 Heap ... -
Java虚拟机垃圾回收机制
2011-03-13 09:31 772一、相关概念 基本 ... -
JVM结构
2011-03-10 14:43 865类文件格式 JVM使用一 ... -
OOM与JVM(转)
2009-03-24 15:49 900OOM与JVM(转) 2008年08月08日 星期五 15: ...
相关推荐
- 永久代(Permanent Generation) 当一个对象被创建时,它首先进入新生代,之后有可能被转移到老年代中。新生代存放着大量的生命很短的对象,因此新生代在三个区域中垃圾回收的频率最高。为了更高效地进行垃圾回收...
ermGen space的全称是Permanent Generation space,是指内存的永久保存区域OutOfMemoryError: PermGen space从表面上看就是内存益出,解决方法也一定是加大内存。说说为什么会内存益出:这一部分 用于存放Class和...
字符串在java程序中被大量使用,为了避免每次都创建相同的字符串对象及内存分配,JVM内部对字符串对象的创建做了一定的优化,在Permanent Generation中专门有一块区域用来存储字符串常量池(一组指针指向Heap中的...
PermGen space的全称是Permanent Generation space,是指内存的永久保存区域。这一部分用于存放Class和Meta的信息,Class在被 Load的时候被放入PermGen space区域,它和和存放Instance的Heap区域不同,GC(Garbage ...
for hrush less permanent-niaghei motors ever It is dcnigncd to sent the modern computer based generation of mo;or engineers, '['he book. uoe» hand-in-hand with modern software-based tedwiquer- for ...
前言 与C语言不同,Java内存...为了进行高效的垃圾回收,虚拟机把堆内存划分成新生代(Young Generation)、老年代(Old Generation)和代(Permanent Generation)3个区域。 新生代 新生代由 Eden 与 S
All Operating Region Power Control of Permanent Magnet Synchronous Wind Power Generation Systems Based on Inverse System Method
永磁同步电机PMSM空间矢量控制SVPWM 仿真模型
Stresses above those listed under Absolute Maximum Ratings may cause permanent damage to the device. This is a stress rating only; functional operation of the device at these or any other conditions ...
23.4 Next-Generation HDI Processes / 23.33 References 23.37 Part 6 Fabrication Chapter 24. Drilling Processes 24.3 24.1 Introduction / 24.3 24.2 Materials / 24.4 24.3 Machines / 24.11 24.4 Methods / ...