JVM之理解

可以说从刚开始学java之后会有很长时间不会接触到jvm这个东西,直到有一天tomcat出现:

场景一:
这里写图片描述
场景二:
这里写图片描述
然后你为了解决问题,为了理解jvm,就开始打开网页花式搜资料,然后就找到了这里。。。

在jvm之初识(https://blog.csdn.net/tuesdayma/article/details/79600075)篇中我们已经提到:jvm中的栈、本地方法栈和程序计数器是线程独享的,而方法区和堆是内存共享的。所以个人觉得,jvm的结构应该定义成这样更为直观:
这里写图片描述
个人理解:

  • 前端没发出一次请求,都会从jvm总体内存中分配一个新的栈、本地方法和程序计数器出来,但是方法区和堆是不会重新创建的
  • jvm的总体内存=堆内存+方法区+线程数*(栈内存+本地方法栈内存)(程序计数器内存忽略不记)
  • Xms、Xmx、Xmn分别表示的是jvm堆内存的起始值、最大值和最小值,并不是jvm总体内存的大小(网上很多文章模棱两可的说是jvm内存。。。);32 位 JVM 最大堆大小 (-Xmx) 被限制为最大 1.5 Gb。64 位 JVM 最大堆大小可为任意大小,但网上说它应小于 28 GB。
  • -Xss表示每个线程的堆栈大小。JDK5.0以后每个线程堆 栈大小为1M,以前每个线程堆栈大小为256K。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一 个进程内的线程数还是有限制的,不能无限生成,大致在3000~5000左右。

三大OOM:

在jvm中只有程序计数器是没有设置OOM这个异常的,他是一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器,如果线程执行的是java方法,这个计数器记录的就是正在执行的虚拟机字节码指令的地址。如果正在执行的是native方法,这个计数器的值为undefined

1、Java Heap Space:堆内存溢出

java堆用于存储对象实例,我们新创建的对象会出现在堆的新生代的伊甸园区,当我们不断创建对象时,伊甸园区会被塞满,然后就回进入轻度GC,幸存下来的对象将会进入幸存者1区,当幸存者1区塞满之后又会轻度GC,幸存下来的将会进入幸存者2区,幸存者2区塞满之后将会轻度GC出新生到去养老代,当养老代快,满的时候将会深度GC,如果养老代满了就回报异常OOM

一般出现堆内存溢出很有可能就是死循环里面在new对象、数据库中查询结果庞大而没有分页、或者是IO的时候内容较多

2、Unable to Create new native thread:栈内存溢出

栈的溢出其实有两种:StackOverflowError、OutOfMemoryError

  • StackOverflowError:

    在刚开始接触java的时候就遇到过,那时候应该是使用了递归调用,进入死循环了。
    其实这个错误是由单个栈内存溢出引起的,默认一个线程栈的大小为1M,也就是说在这个线程栈中只要有1M的东西被入栈而没有出栈的话,就会报StackOverflowError这个异常

  • OutOfMemoryError:Unable to Create new native thread

    这个异常应该是jvm没有足够的内存开辟出一个新的栈内存出来,就会报这个异常;个人觉得这个异常在64位的jdk中是不会发生的,因为网上好像都说64位的jdk,jvm的最大内存取决于操作系统的物理内存,而对于32位的jdk来说,jvm最大貌似只有1.5G到2G之间,也就是说,堆分配1G内存走的话,最多只能创建500个线程,当然可以减少堆内存或者降低Xss来提高能创建的线程数,但是降低Xss容易引起StackOverflowError,减少堆内存容易造成堆内存溢出

3、PermGen space:方法区溢出 (这个参考网上的)

异常信息:java.lang.OutOfMemoryError:PermGen space

方法区用于存放Class的相关信息,如类名、访问修饰符、常量池、字段描述、方法描述等。

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

方法区溢出也是一种常见的内存溢出异常,一个类如果要被垃圾收集器回收,判定条件是很苛刻的。在经常动态生成大量Class的应用中,要特别注意这点。

经典设置:参考于:http://pengjiaheng.iteye.com/blog/538582

-Xmx3550m:设置JVM最大可用内存为3550M。
-Xms3550m:设置JVM促使内存为3550m。此值可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存。
-Xmn2g:设置年轻代大小为2G。整个堆大小=年轻代大小 + 年老代大小 + 持久代大小。持久代一般固定大小为64m,所以增大年轻代后,将会减小年老代大小。此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8。
-Xss128k:设置每个线程的堆栈大小。JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K。更具应用的线程所需内存大小进行调整。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右。

-XX:NewRatio=4:设置年轻代(包括Eden和两个Survivor区)与年老代的比值(除去持久代)。设置为4,则年轻代与年老代所占比值为1:4,年轻代占整个堆栈的1/5
-XX:SurvivorRatio=4:设置年轻代中Eden区与Survivor区的大小比值。设置为4,则两个Survivor区与一个Eden区的比值为2:4,一个Survivor区占整个年轻代的1/6
-XX:MaxPermSize=16m:设置持久代大小为16m。
-XX:MaxTenuringThreshold=0:设置垃圾最大年龄。如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代。对于年老代比较多的应用,可以提高效率。如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活时间,增加在年轻代即被回收的概论。

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值