2021-06-16 方法区优化 学习

方法区

方法区 一样 都会有 OOM 我们可以动态调节 方法区的大小,也可以给他固定的大小,并且方法去也会存在垃圾回收

堆栈方法区的交互关系

    • 方法对象的
    • 当前运行的方法已经方法的变量和指向堆内存的地址的服务引用
  • 方法区
    • 运行需要的所有的字节码文件
class Test {
    public static void main(String[] args) {
        TestDemo testDemo = new TestDemo();
        /*
        testDemo : 栈空间
        TestDemo : 方法区
        new TestDemo() : 堆空间
        */
    }
}

class TestDemo {
    private int i;
    
    public int getI() {
        return i;
    }
}

方法区的理解

方法区和堆空间一样都是各个线程共享的内存区域。

关闭 JVM 就会释放这个区域的内存

设置方法区的大小和OOM

  • 1.7 和 之前版本:

    • -XX:PermSize=大小 最小的
    • -XX:MaxPermSize=大小 最大的
  • 1.8 和以后版本:

    • -XX:MatespaceSize=大小 最小的
    • -XX:MaxMatespaceSize=大小 最大的
      • 如歌等于 -1 就是对大小不做限制。物理内存可用的最大值

如何解决和处理 方法区的OOM

可以导出堆的快照,然后用第三方工具分析(eclipse memory analyzer; JProfile; jvisvm),然后查出是 内存泄漏 还是 内存溢出

  • 如果是内存溢出,则需要看一下堆的对象和引用链中的 GC ROOT 是否存在不被使用但是对象没有被 GC 回收的事情,如果存在则需要处理掉这些。
  • 如果是内存溢出。看一下是堆溢出还是栈溢出可以适当调节堆栈内存

注:内存溢出:存在不被代码使用已经废弃的对象,但是没有被垃圾回收器回收的对象

方法区的内部结构

jdk 1.8 之前是 永久代 1.8 以后就是 元空间

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Mo7BDXMh-1624614944587)(C:\Users\L\AppData\Roaming\Typora\typora-user-images\image-20210614163815854.png)]

字符串常量池再不同的 jdk 版本是不一样的

1.7 及之前,是存在方法区的,1.8 及以后是存在堆空间的。

方法区使用举例

方法区的演进细节

1、描述

只有 Hosport 才有永久代,Ibm 的 J9 和 jrockit 是没有永久代的是有元空间

2、Hosport 永久代的变化

jdk 版本Jdk 各个版本的演进变化
1.6 及 之前有永久代(permanent generation),静态变量存储在永久代上面。
1.7有永久代,但已经逐步去永久代,字符串常量池、静态变量移除,保存在堆中。
1.8 及 以后没有永久代,类型信息,字段,方法,常量保存在本地元空间,但字符串常量池、静态变量仍在堆。

3、替换的原因

  • 在某些情况下,如果 Perm 区域 动态加载类太多容易产生 OOM 。
    • 比如在世家的 web 场景下,因为功能点比较多,在运行过程中。要不断地的动态加载很多的类,经常出现致命错误(OOM)
      • Exception in thread 'dubbo client xxx connector' java.lang.OutOfMemaryError:PermGen
    • 永久代空间和元空间最大的区别在于:
      • 元空间:
        • 不是虚拟内存的映射而是机器的真实内存,默认情况下只受本地内存的限制
      • 永久代:
        • 虚拟内存的映射

方法区的大小和 OOM

元空间:设置方法区的初始值和最大值。默认 方法区最大为 -1 最小的为 21M

设置方式:-XX:MatespaceSize=size 初始值 -XX:MaxMatespaceSzie=size 最大值

一般我们不会修改最大值但是我们会一定程度的修改最小的值,因为每一次最小的值的提升必定伴随着一个 FULL GC。而 FULL GC 往往也会伴随着系统性能的消耗, SWT。

StringTable 为什么会被放到堆空间

因为在永久代里面的数据只有在 FULL GC 的时候才回去只写哪个回收,所以回收效率很低。而 FULL GC 只有在永久代内存不足、堆内存不足,才会执行。而我们开发当中会创建很多的字符串。会少效率低,导致永久代的内存不足。放到堆里面可以提升回收效率。

只有new的对象都会放在堆内存。

JHSDB

JDK 9 以后系统附带的工具

方法区的垃圾回收

只会有 FULL GC

**常量池的回收,**只要常量池没有被任何地方引用,就可以被回收。

类的回收,必须同时满足三个条件才可以进行回收

1:class类不被使用,且他的子类也不会被使用

2:classloader 被回收

3:该类对应的 Class 的类没有被任何地方引用(避免有反射的类的存在)

总结

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值