方法区内存溢出及常量池
22 方法区-定义
是所有线程共享的一块区域。 存储了和类结构相关信息。运行时常量池, 方法区在虚拟机启动时被创建,逻辑上是堆的组成部分。 方法区内存不足,也会导致oom异常。 是一个概念上的东西, 1.6使用永久代作为方法区,类和类加载器。还有运行时常量池,串池。 1.8 Metaspace 元空间,类,类加载器,常量池,不占用堆空间,不由jvm管理,占用操作系统内存。
23 方法区——内存溢出
ClassLoader 用来加载类的二进制字节码。 循环1000次,是否会因为类加载过多,导致方法去内存溢出。 -XX:MaxMetaspaceSize=8m 演示元空间内存溢出问题。 1.8以前导致永久代内存溢出; 1.8以后导致元空间内存溢出。
24 内存溢出
场景 spring mybatis 都使用了cglib,动态代理核心
25 方法区——常量池
什么叫常量池? javap -v Helloworld.class 反编译 java源代码变成虚拟机指令。 查表翻译 #2 查询常量池的表。 给指令提供一些常量符号,查表方式找到他们。
26 方法区-运行时常量池
是一张表,虚拟指令从里面找,执行的类名,方法名,参数,字面量等信息。 运行时常量池,当类被加载,它的常量池就会被放到运行时常量池(内存中),地址变为真实地址。
27 StringTable面试题
28 常量池和串池的关系
ldc #2 把a符号变为"a"字符串对象。 每个字符串对象都不是事先放到串池,而是用到才开始创建字符段对象,是懒惰的行为。 StringTable ["a","b","ab"] hashtable结构,不能扩容。 astore 存储 aload 从表中拿到
29 字符串变量拼接
测试代码
public class Demo1_22 { public static void main(String[] args) { String s1="a"; String s2="b"; String s3="ab"; String s4=s1+s2; System.out.println(s3==s4); } } //new StringBuilder().apend("a").append("b").toString() new String("ab")
结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mSXxsJia-1691329173338)(C:UsersAdministratorAppDataRoamingTypora ypora-user-imagesimage-20230806163553488.png)]
30 编译器优化
javac在编译期的优化,都是常量,拼接的结果已经确定了。
代码
public class Demo1_22 { public static void main(String[] args) { String s1="a"; String s2="b"; String s3="ab"; String s4=s1+s2; String s5="a"+"b"; System.out.println(s3==s5); } }
31 字符串延迟加载
使用menmery工具,没有存在的对象会进行加载,已经存在的对象就不去新增。