JVM虚拟机内存

JVM运行时内存组成分为一些线程私有的,其他的是线程共享的。

线程私有

  • 程序计数器:当前线程所执行的字节码的行号指示器。
  • Java虚拟机栈:java方法执行的内存模型,每个方法被执行时都会创建一个栈帧,存储局部变量表,操作栈,动态链接,方法出口等信息。每个线程都有自己独立的栈空间,线程栈只存储基本类型和对象地址,方法中局部变量存放在线程空间中。
  • 本地方法栈:Native方法服务,在hotspot虚拟机中和java虚拟机栈合二为一。

线程共享

  • java堆:存放对象实力,几乎所有的对象实例及其属性都在这里分配内存。此外,jvm在内存新生代eden space中开辟了一块线程私有的区域,称作TLAB(Thread Local Allocation Buffer),也是每个线程的缓冲区,默认设定为占用Eden space的1%。在编译器做逃逸分析的时候,根据分析结果,决定是在栈上还是在堆上分配内存,如果在堆上则再分析是否在TLAB上分配内存。在TLAB上分配由于是线程私有的,因此没有锁的开销,效率较高。
  • 方法区:存储已经被虚拟机加载的类信息,常量,静态变量,JIT编译后的代码等数据,也称作永久代。java7已经把字符串常量池移动到堆中,在调用String的intern方法时,如果堆中存在相同的字符串对象,会直接保存对象的引用,不会重新创建对象。
  • 直接内存:NIO,Native函数直接分配的堆外内存。DirectBuffer引用会使用此部分内存。

内存分配过程

  1. 编译器通过逃逸分析,确定对象是在栈上分配还是堆上分配。如果在堆上分配直接进入步骤4。
  2. 如果是tlab_top + size <= tlab_end,则在TLAB上直接分配对象并增加tlab_top的值。如果现有TLAB不足存放当前对象则进入步骤3。
  3. 重新申请一个TLAB,并再次尝试存放当前对象,如果放不下,则进入步骤4。
  4. 在Eden区加锁(此区多线程共享),如果eden_top + size <= eden_end,则将对象存放在eden区,增加eden_top的值,如果eden区不足以存放,则进入步骤5。
  5. 执行一次YGC。
  6. 经过YGC后,如果eden还放不下对象,则直接分配到老年代。

对象访问

  • 句柄访问:通过栈本地变量表,找到堆中对象实例指针,根据指针在堆中找到实例数据,在方法区中找到对象类型数据。
  • 直接指针:通过栈本地变量表,找到堆中对象实例指针,对象实例指针中保存对象实例数据,在方法区中找到对象类型数据。

对象创建

  • 对象在eden完成内存分配。
  • eden满了,在创建对象,会因为申请不到空间,触发minor gc,堆eden+s 区进行回收。
  • 进行minor gc时,eden区不能被回收的对象进入s区,另一个s区中不能被gc回收的对象也会进入这个s区,始终保证一个s区空置。
  • 如果s区满了,这些对象会被copy到old区,或者s区没有满,但是有些对象足够old了,会被放入old区。
  • old区满了之后,进行full gc。

内存溢出

在JVM申请内存的过程中,会遇到无法申请到足够内存的情况,从而导致内存溢出。

  • 虚拟机栈和本地方法区栈溢出:statkoverflowerror:线程请求的栈深度大于虚拟机所允许的最大深度,循环递归会触发这种OOM。outfomemoryerror:虚拟机在扩展栈时无法申请到足够的内存空间,一般可以通过不停创建线程触发这种OOM。
  • java堆溢出:创建大量对象并且对象生命周期很长情况时,会引发outofmemoryerror。
  • 方法区溢出:方法区存放class等元数据信息,如果产生大量的类(如CGLIB),会引发这种内存溢出,outofmemoryerror:permgen space,在使用hibernate等动态生成类框架时会引起这种情况。

垃圾回收和系统吞吐量

  • 吞吐量:指的是单位时间内完成的工作量的度量。
  • 响应时间:是提交请求和返回该请求的响应之间使用的时间。

通常平均响应时间越短,系统吞吐量越大,平均响应时间越长,吞吐量越小。

  • 并行垃圾回收器关注的是吞吐量,会在一定程度上牺牲响应时间。可能某次请求会特别慢。
  • 并发垃圾回收器关注的是请求响应时间,会牺牲吞吐量。会尽量使得每次请求时间维持在差不多水平。

对于CMS触发full gc的情况:

  • old区使用到一定比例时触发,通过cmsinitiatingoccupancyfaction来设置。

本文分享自微信公众号 - 春哥叨叨(chungedaodao),作者:春哥大魔王

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-04-21

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 线程的阻塞和唤醒

    park方法有两个参数来控制休眠多长时间,第一个参数isAbsolute表示第二个参数是绝对时间还是相对时间,单位是毫秒。

    春哥大魔王
  • 获取线程池中任务执行数量

    通过ThreadPoolExecutor的相关API实时获取线程数量,排队任务数量,执行完成线程数量等信息。

    春哥大魔王
  • JAVA NIO内存泄漏

    前言 写NIO程序时,经常使用ByteBuffer来读取写入数据,那使用ByteBuffer.allocate()还是ByteBuffer.allocateDi...

    春哥大魔王
  • 第二篇:JVM内存结构和Java内存模型

    其实并不想写这一篇文章,原因是这个东东只要是Java开发者都知道的内容,大部分都是偏理论性的,但是为了方便后续文章的开展,所以还是着手描写一下我个人对JVM的了...

    Liusy
  • JVM内存模型

    java404
  • BAT面试必问题系列:深入详解JVM 内存区域及内存溢出分析

    在JVM的管控下,Java程序员不再需要管理内存的分配与释放,这和在C和C++的世界是完全不一样的。所以,在JVM的帮助下,Java程序员很少会关注内存泄露和内...

    Java搬砖工人
  • 我也想从零开始了解一下JVM虚拟机

    采用最原始的方式运行Java文件,打开任务管理器我们可以看到一个java.exe,是的,这个就是Java虚拟机,当10秒过后,main方法执行结束,java.e...

    用户7386338
  • golang语言是如何处理栈的

    Go 1.4Beta1刚刚发布,在Go 1.4Beta1中,Go语言的stack处理方式由之前的"segmented stacks"改为了"continuous...

    李海彬
  • JVM各区溢出分析

    由于在Hotspot虚拟机中中不区分虚拟机栈和本地方法栈,因此通过-Xoss修改参数是无效的,可以通过修改-Xss设定。

    java乐园
  • 应用:基于自然语言识别下的流失用户预警

    update: 17.12.20 : 关于IDF处描述,经@余海跃同学提醒,细化了解释内容,感谢! 更新内容参见:基于自然语言识别下的流失用户预警

    sladesal

扫码关注云+社区

领取腾讯云代金券