JVM常见问题

(一)JVM内存模型和分区,每个分区放什么?

  • Java内存模型(即Java Memory Model,简称JMM)本身是一种抽象的概念。java内存模型中分为主内存工作内存主内存可粗略认为是工作内存认为是
  • 主内存里面存储着所有变量,属于共享内存区域,所有线程都可以访问。
  • 每一个线程都私有一个工作内存,保存着主内存里面变量值的副本,线程对变量的操作都是在工作内存中完成,操作结束后再放回主内存。
  • 操作系统中,一般CPU都会从内存取数据到寄存器,然后进行处理,但由于内存的处理速度远远低于CPU,导致CPU在处理指令时往往花费很多时间在等待内存做准备工作,于是在寄存器和主内存间添加了CPU缓存,CPU缓存比较小,但访问速度比主内存快得多。所以Java虚拟机在程序执行过程会把jvm的内存分为若干个不同的数据区域。有:堆,栈,方法区,程序计数器,本地方法栈
  1. 堆: 类,方法,常量,变量,保存我们所有引用类型的真实对象。
  2. 栈: 八种基本类型变量+对象的引用变量,栈操作,栈帧数据。
  3. 方法区: 静态变量,常量,类信息(构造方法,接口定义),运行时的常量池存在方法区中,但是实例变量存在堆内存中,和方法区无关。方法区存储了每一个类的结构信息,就是模板的意思。
  4. 程序计数器: 可以简单理解为一个指针,里面存的就是下一个将要执行的的方法的指针。
  5. 本地方法栈: 装native方法专用的栈,这是一个特殊的栈JNI
  • 补充:常量池在1.7中处于永久代,但在1.8中,处于堆中,因为1.8中,永久代变成了元空间,但是元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存限制,所以可以通过参数调优来指定元空间的大小。

(二)堆里面的分区以及特点。

  • 堆里面分为新生代和老生代(java8取消了永久代,采用了元空间Metaspace),新生代包含伊甸园区和幸存区Eden+Survivor区,survivor区里面分为from和to区,内存回收时,在新生代使用的是复制算法,从from复制到to,当经过一次或者多次GC之后,存活下来的对象会被移动到老年区,当JVM内存不够用的时候,会触发重GC(Full GC),清理JVM老年区。

  • 当新生区满了之后会触发YGC,先把存活的对象放到其中一个Survice区,然后进行垃圾清理。因为如果仅仅清理需要删除的对象,这样会导致内存碎片,因此一般会把Eden 进行完全的清理,然后整理内存。那么下次GC 的时候,就会使用下一个Survive,这样循环使用。如果有特别大的对象,新生代放不下,就会使用老年代的担保,直接放到老年代里面。因为JVM 认为,一般大对象的存活时间一般比较久远。

  • 补充: 1.7之前新生代和老年代都在java堆,永久代在方法区,1.8之后变换为元空间,元空间使用本地内存。

(三)如何解决OOM问题?

  • 内存泄露: 申请使用完的内存没有释放,导致虚拟机不能再次使用该内存,此时这段内存就泄露了,因为申请者不用了,而又不能被虚拟机分配给别人使用。

  • 内存溢出: 申请的内存超出了JVM能提供的内存大小,此时称之为溢出。

  • 用来存放JDK自身携带的Class对象,Interface元数据,存储的是java运行时的一些环境或者类信息,这个区域不存在垃圾回收,关闭JVM虚拟机会释放这个区域的内存。
    例如:一个启动类,加载了大量的第三方jar包,Tomcat部署了太多的应用,大量动态生成的反射类,不断地被加载,直到内存满,就会出现OOM

  • OutOfMemory出现的原因:

  1. 分配的少了:比如虚拟机本身可使用的内存(一般通过启动时的VM参数指定)太少。
  2. 应用用的太多,并且用完没释放,浪费了。此时就会造成内存泄露或者内存溢出。
  • 如何解决?
  1. 能够看到代码第几行出错:内存快照分析工具,MAT,Jprofiler工具
  2. Dubug,一行行分析代码。(效率低下)
  • MAT,JProfiler 的作用:
  1. 分析Dump文件,快速定位内存泄漏

-Xms1m -Xmx8m -XX:+HeapDumpOnOutOfMemoryError

-Xms 设置初始化内存分配大小
-Xmx 设置最大分配内存,默认1/4
-XX:+PrintGCDetails  打印GC垃圾回收信息
-XX:+HeapDumpOnOutOfMemoryError
  1. 获得堆中的数据
  2. 获得大的对象

(四)堆内存调优

  • 默认情况下,分配的总内存,是电脑的1/4,而初始化的内存是1/16

在这里插入图片描述- 在配置中修改参数语句:

-Xms1024m -Xmx1024m -XX:+PrintGCDetails

在这里插入图片描述

(五)元空间调优

  • 元空间虚拟机控制元空间的增长。但是有些时候我们想限制其增长,比如通过显式在命令行中设置-XX:MaxMetaspaceSize。默认情况下,-XX:MaxMetaspaceSize的值没有限制,因此元空间甚至可以延伸到交换区,但是这时候当我们进行本地内存分配时将会失败。
  • 对于一个64位的服务器端JVM来说,其默认的–XX:MetaspaceSize值为21MB。这就是初始的高水位线。一旦触及到这个水位线,Full GC将会被触发并卸载没有用的类(即这些类对应的类加载器不再存活),然后这个高水位线将会重置。新的高水位线的值取决于GC后释放了多少元空间。如果释放的空间少,这个高水位线则上升。如果释放空间过多,则高水位线下降。如果初始化的高水位线设置过低, 上述高水位线调整情况会发生很多次。通过垃圾回收器的日志我们可以观察到Full GC多次调用。为了避免频繁的GC,可以将–XX:MetaspaceSize设置为一个相对较高的值。
  • 经过多次GC之后,元空间虚拟机自动调节高水位线,以此来推迟下一次垃圾回收到来。有这样两个选项 XX:MinMetaspaceFreeRatioXX:MaxMetaspaceFreeRatio,他们类似于GC的FreeRatio选项,用来设置元空间空闲比例的最大值和最小值。我们可以通过命令行对这两个选项设置对应的值。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值