JVM运行时内存区域

5 篇文章 0 订阅

1. JVM数据区域

JVM数据区域分两类,一类生命周期随vm,一类生命周期随thread。

 

2. pc寄存器(线程独占)

JVM在设计上支持多个线程同时执行(硬件上适配多核cpu是真正意义上的并行),为此每个线程都有属于自己的pc register,注意这里的指令寄存器并不是8086这样cpu架构里的pc register,JVM里的pc register只是抽象的概念,并不对应具体的硬件设备。

 

3. JVM栈(线程独占)

每个线程都有一个私有的jvm栈,里面存放着一组frame,每个frame记录着程序跳转时候的运行状态切面。

JVM栈可以设计成定长或可动态扩容,当定长容量突破阈值时,JVM抛出StackOverflowError;当变长容量突破JVM内存总量的阈值时,JVM抛出OutOfMemoryError。

hotspot实现中,线程栈大小和JVM运行环境有关:

You may be running into a problem with the default stack size for threads. In Java SE 6, the default on Sparc is 512k in the 32-bit VM, and 1024k in the 64-bit VM. On x86 Solaris/Linux it is 320k in the 32-bit VM and 1024k in the 64-bit VM.

On Windows, the default thread stack size is read from the binary (java.exe). As of Java SE 6, this value is 320k in the 32-bit VM and 1024k in the 64-bit VM.

You can reduce your stack size by running with the -Xss option. For example:

java -server -Xss64k

 

4. native方法栈(线程独占)

用于支持非java语言运行时的栈使用需求,每个线程具有一个私有的native方法栈,随线程创建和销毁。native方法栈和JVM栈一样会在内存不够用时抛出StackOverflowError或OutOfMemoryError。

 

5. 堆(线程共享)

JVM的堆由所有线程共享,对象和数组都放在里面,申请超出heap内存分配能力的行为会使JVM抛出OutOfMemoryError。

堆空间在hotspot实现中分为,old区,eden区,survivor区(不同jdk版本还有一些元信息也放在堆)。

 

6. 方法区(线程共享)

方法区被所有线程共享,存放.class文件信息(运行时常量池,编译后的代码,字段,方法。。。详情见class文件结构)。方法区内存不够用也会导致JVM抛出OutOfMemoryError。运行时常量池对应于class文件的常量池,在每个类或接口加载时被创建。

hotspot实现中,jdk7和之前的版本中存在perm区(类的元信息、静态变量、字符串常量),jdk7版本里,字符串常量、类的静态变量被移到了堆中,符号表移到native memory,这是perm区的第一次裁剪,而到了jdk8中则完全取消了perm区,新增了metaSpace。而metaspace中仅存放之前perm区里的类元信息,metaspace也被放在native memory中。

perm区有大小限制,超出后会造成oom,而metaSpace则直接使用操作系统内存(native memory),没有大小限制(但通常使用-XX:MaxMetaspaceSize做限制)。另外移除 PermGen 可以促进 HotSpot JVM 与 JRockit VM 的融合,因为 JRockit 没有永久代。

perm区在jdk1.5和jdk6里默认不会被gc回收,但可以显式开启,此时会在FGC阶段被回收。

 

从jdk8开始,使用metaspace存放类元信息和一些其它元信息,此时可能出现Compressed Class Space的概念。这也是一块内存区域,和metadata一样放在native memory里,当UseCompressedClassesPointers属性是enable的时候,会生成Compressed Class Space(CCS)内存区块(缺省就是enable)(CCS还是metadata的一部分)。CCS里存放的是类的元信息(不知道此时metadata里还存了什么)。CCS名称中有Compressed,这代表着此时代码中类元信息的引用被压缩。对64位操作系统而言,引用默认使用64bis表示,但java应用通常不需要这么大的寻址范围。为了节约内存使用,引入了CCS区域存放由32bis指向的类元信息。在JDK6和JDK7中有UseCompressedOops属性,同CCS解决同样的问题。CCS默认情况下是1G,超限会抛出OOM。

Code Cache内存区域分布在native memory,用于存放jit编译的结果。随着程序执行,code cache面临溢出的问题,溢出会触发回收,回收不掉会抛出java HotSpot(TM) 64-Bit Server VM warning: CodeCache is full. Compiler has been disabled。此时JIT功能被影响,程序运行效率降低。网上看到JDK8的回收效率要由于JDK7。code cache的大小通过-XX:ReservedCodeCacheSize=256M控制。

 

7. 哨兵监控G1内存使用图

 

相关内容参考:

https://www.oracle.com/webfolder/technetwork/tutorials/mooc/JVM_Troubleshooting/week1/lesson1.pdf

https://docs.oracle.com/javase/specs/jvms/se8/html/index.html

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值