第二章:方法区和运行时常量池溢出

由于运行时常量池属于方法区的一部分,因此两个区域放在一块执行。

String.intern()是一个Native方法,它的作用是如果字符串常量池中已经包含了此String对象的字符串,则返回代表池中这个字符串的String对象;否则将此String对象包含的字符串添加到常量池中,并且返回此String对象的引用。

可以通过以下代码测试运行时常量池溢出:

public class Test {
 public static void main(String[] args) {
 int i =0;
 List<String> list = new ArrayList();
 while(true) {
 list.add(String.valueOf(i++).intern());
 }
 }
}

可以在抛出的异常后面发现“Perm space”信息。

可以使用String.intern()测试运行时常量池:

public class Test1 {
 public static void main(String[] args) {
 String str1 = new StringBuilder("111").append("-222").toString();
 System.out.println(str1.intern()==str1);
 String str2= new StringBuilder("jav").append("a").toString();;
 System.out.println(str2.intern()==str2);
 }
}
结果:
true
false

JDK1.7中的intern实现不会复制实例,只是在常量池中记录首次出现的实例引用,因此intern()返回的引用和由StringBuilder创建的那个字符串实例是同一个。

对str2比较返回false是因为“java”字符串在执行StringBuilder.toString()之前已经出现过了,字符串常量池中已经有它的引用了,不符合“首次出现”的原则。

方法区用于存放Class相关的信息,如类名、访问修饰符、常量池、字段描述、方法描述等,对于这些区域的测试,基本的思路是运行时产生大量的类填充方法区,直到溢出。

可以借助GCLib直接操作字节码运行时产生大量的动态类:

public class Test1 {
public static void main(final String[] args) {
while(true){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(OOMOBject.class);
enhancer.setUseCache(false);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
return methodProxy.invoke(objects,args);
}
});
enhancer.create();
}
}
static class OOMOBject{

}
}

除了GCLib字节码增强和动态语言之外,常见的还有大量JSP或者动态生成JSP文件的应用、基于OSGi的应用等

原文地址:https://www.cnblogs.com/use-D/p/10618771.html

时间: 2024-10-04 11:15:52

第二章:方法区和运行时常量池溢出的相关文章

Java方法区和运行时常量池溢出问题分析

运行时常量池是方法区的一部分,方法区用于存放Class的相关信息,如类名.访问修饰符.常量池.字段描述.方法描述等. String.intern()是一个native方法,它的作用是:如果字符串常量池中已经包含了一个等于此String对象的字符串,则返回代表池中这个字符串的String对象:否则,将此String对象包含的字符串添加到常量池中,并返回此String对象的引用.在JDK1.6及之前版本中,由于常量池分配在永久代中(即方法区),我们可以通过-XX:PermSize和-XX:MaxPe

Java方法区和运行时常量池溢出问题分析(转)

运行时常量池是方法区的一部分,方法区用于存放Class的相关信息,如类名.访问修饰符.常量池.字段描述.方法描述等. String.intern()是一个native方法,它的作用是:如果字符串常量池中已经包含了一个等于此String对象的字符串,则返回代表池中这个字符串的String对象:否则,将此String对象包含的字符串添加到常量池中,并返回此String对象的引用.在JDK1.6及之前版本中,由于常量池分配在永久代中(即方法区),我们可以通过-XX:PermSize和-XX:MaxPe

方法区和运行时常量池

方法区和运行时常量区溢出 转

方法区和运行时常量池溢出 由于运行时常量池是方法区的一部分,因此这两个区域的溢出测试就放在一起进行.前面提到JDK 1.7开始逐步“去永久代”的事情,在此就以测试代码观察一下这件事对程序的实际影响. String.intern()是一个Native方法,它的作用是:如果字符串常量池中已经包含一个等于此String对象的字符串,则返回代表池中这个字符串的String对象:否则,将此String对象包含的字符串添加到常量池中,并且返回此String对象的引用.在JDK 1.6及之前的版本中,由于常量

探讨:编译时常量和运行时常量

编译时常量和运行时常量 C#有2种不同的常量定义方式:编译时常量(compile-time)和运行时常量(runtime).他们的行为方式有很大的不同,如果选用了错误的一个,那么将让程序的性能和正确性产生商榷.当然,一个系统最好没有任何问题,但是如果一定会存在一个问题,那么一个稍慢的但强壮的系统比一个速度更快的但很脆弱的系统要好.基于以上理由,在二者选其一的时候,你最好选择运行时常量. 运行时常量以 readonly 关键字定义,编译时是常量以 const 关键字定义: public const

JVM【第七回】:【OutOfMemoryError异常之运行时常量池溢出】

如果要向运行时常量池中添加内容,最简单的做法就是使用String.intern()这个Native方法.该方法的作用是:如果池中已经包含一个等于此String对象的字符串,则返回代表池中这个字符串的String对象:否则将此String对象包含的字符串添加到常量池中,并且返回此String对象的引用.由于常量池分配在方法区内,我们可以通过-XX:PermSize和-XX:MaxPermSize限制方法区的大小,从而间接限制其中产量池的容量:代码如下: package oom; import ja

Java虚拟机OOM之运行时常量池溢出(5)

如果要向运行时常量池中添加内容,最简单的做法就是使用 String.intern()这个 Native 方法.该方法的作用是:如果池中已经包含一个等于此 String 对象的字符串,则返回代表池中这个字符串的String 对象:否则,将此 String 对象包含的字符串添加到常量池中,并且返回此 String 对象的引用.由于常量池分配在方法区内,我们可以通过-XX:PermSize 和-XX:MaxPermSize 限制方法区的大小,从而间接限制其中常量池的容量代码运行时常量池导致的内存溢出异

第二章:数据类型和运算符

第二章:数据类型和运算符 计算机中的进制 **标识符 总的命名规则:见名知意.如果有多个单词组成,首单词小写,其余单词的首字母大写(驼峰命名法).1.首字母只能是字母,下划线和$2.其余字母可以字母,下划线,$和数字3.不能使用预留关键字4.严格区分大小写 数据类型*** 基本数据类型 整型 byte(1个字节) short(2个字节) int(4个字节) long(8个字节) 浮点型 float(4个字节) double(8个字节) 字符型 char(2个字节)采用Unicode码 布尔型 b

第二章 变量,数据类型和运算符

第二章 &变量,数据类型和运算符 英文新识: double 双精度浮点 string  字符串 character  字母 integer  整数 Scanner  扫描仪 score  分数         name  名字     boolean  布尔   true  真          false  假 语法新知: double score =98.5; //声明双精度浮点型变量score存储分数 String name="张大侠";        //声明字符串型变