JVM内存结构
来源:互联网 发布:湖人vs公牛球员数据 编辑:程序博客网 时间:2024/05/22 08:04
1、为什么要了解JVM内存管理机制
- JVM自动的管理内存的分配与回收,这会在不知不觉中浪费很多内存,导致JVM花费很多时间去进行垃圾回收(GC)
- 内存泄露,导致JVM内存最终不够用
2、JVM内存结构
根据上图,JVM内存结构包括:
- 方法区(也就是"持久代")
- 堆
- 栈(在hotspot JVM中,JVM方法栈--Java虚拟栈,与本地方法栈是同一个)
- PC寄存器(程序计数器)
注意点:
- 堆是GC的主要区域,方法区也会发生GC
- 栈与PC寄存器是每个线程都会创建的私有区域,不会GC
2.1、方法区
- 存放内容(类的信息、类static属性、方法、常量池)
- 已经加载的类的信息(名称、修饰符等)
- 类中的static变量
- 类中的field信息
- 类中定义为final常量
- 类中的方法信息
- 运行时常量池:编译器生成的各种字面量和符号引用(编译期)存储在class文件的常量池中,这部分内容会在类加载之后进入运行时常量池,class文件的常量池查看 第三章 类文件结构与javap的使用
- 使用实例:反射,在程序中通过Class对象调用getName等方法获取信息数据时,这些信息数据来源于方法区。
- 调节参数
- -XX:PermSize:指定方法区的最小值,默认为16M
- -XX:MaxPermSize:指定方法区的最大值,默认为64M
- 所抛错误
- 方法区域要使用的内存超过了其允许的大小时,抛出OutOfMemoryError
- 内存回收的主要目标
- 对类的卸载(这也是为什么很多企业使用velocity等模板引擎做前端而不是使用jsp的原因之一)
- 针对常量池的回收
- 总结
- 一般而言,在企业开发中,-XX:PermSize==-XX:MaxPermSize
- 通常,这个大小设置为256M就没问题了,当然还要根据自己的程序去预估,并在运行过程中去调整,这里以在Resin服务器中配置为例View Code
- 类中的static变量会在方法区分配内存,但是类中的实例变量不会(类中的实例变量会随着对象实例的创建一起分配在堆中,当然若是基本数据类型的话,会随着对象的创建直接压入操作数栈)
- 关于方法区的存放内容,可以这样去想所有的通过Class对象可以反射获取的都是从方法区获取的(包括Class对象也是方法区的,Class是该类下所有其他信息的访问入口)
2.2、堆
- 存放内容
- 对象实例(类中的实例变量会随着对象实例的创建一起分配在堆中,当然若是基本数据类型的话,会随着对象的创建直接压入操作数栈),这一点查看 第四章 类加载机制
- 数组值
- 使用实例
- 所有通过new创建的对象都在这块儿内存分配,具体分配到年轻代还是年老代需要根据配置参数而定(新建对象直接分配到年老代有两种情况,看下边)
- 调节参数
- -Xmx:最大堆内存,默认为物理内存的1/4但小于1G
- -Xms:最小堆内存,默认为物理内存的1/64但小于1G
- -XX:MinHeapFreeRatio,默认当空余堆内存小于最小堆内存的40%时,堆内存增大到-Xmx
- -XX:MaxHeapFreeRatio,当空余堆内存大于最大堆内存的70%时,堆内存减小到-Xms
- 注意点
- 在实际使用中,-Xmx与-Xms配置成相等的,这样,堆内存就不会频繁的进行调整了
- 抛出错误
- OutOfMemoryError:在堆中没有内存完成实例分配(关于实例内存的分配,之后再说),此时堆内存已达到最大无法扩展时。
- 堆内存划分
- 新生代
- 组成:Eden+From(S0)+To(S1)
- -Xmn:整个新生代的大小
- -XX:SurvivorRatio:调整Eden:From(To)的比率,默认为8:1
- 年老代
- 新建对象直接分配到年老代,两种情况
- 大对象:-XX:PretenureSizeThreshold(单位:字节)参数来指定大对象的标准,在Parallel Scavenge GC下可能无效,具体见《第五章 JVM垃圾收集器(1) 》
- 大数组:数组中的元素没有引用任何外部的对象
- 新建对象直接分配到年老代,两种情况
- 新生代
- 总结
- 企业开发中,-Xmx==-Xms
- 通常,-Xmx设置为2048m就没问题了,当然还要根据自己的程序去预估,并在运行过程中去调整,这里以在Resin服务器中配置为例View Code
可以看到,-Xms==-Xmx==2048m,年轻代大小-Xmn==512m,这样,年老代大小就是2048-512==1536m,这个比率值得记住,在企业开发中,年轻代:年老代==1:3,而此时,我们配置的-XX:MaxTenuringThreshold=15(这也是默认值),年轻代对象经过15次的复制后进入到年老代(关于这一点,在之后的GC机制中会说),
- -XX:MaxTenuringThreshold与-XX:PretenureSizeThreshold不一样,不要看错
2.3、栈
- 注意点
- 每条线程都会分配一个栈,每个栈中有多个栈帧(每一个方法对应一个栈帧)
- 每个方法在执行的同时都会创建一个栈帧,每个栈帧用于存储当前方法的局部变量表、操作数栈等,具体查看本文第一个图,每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程,说的更明白一点,就是方法执行时创建栈帧,方法结束时释放栈帧所占内存
- 存放内容
- 局部变量表:八大基本数据类型数据、对象引用。该空间在编译期已经分配好,运行期不变。
- 操作数栈:是执行引擎直接操作的部分
- 调节参数
- -Xss:设置栈的大小,通常设置为1m就好View Code
- -Xss:设置栈的大小,通常设置为1m就好
- 支持native方法执行(本地方法栈)
- 所抛错误
- StackOverFlowError:线程请求的栈深度大于虚拟机所允许的深度。
- 典型场景:没有终止条件的递归(递归基于栈)。
- 每个方法的栈的深度在javac编译之后就已经确定了,查看 第三章 类文件结构与javap的使用
- OutOfMemoryError:虚拟机栈可以动态扩展,如果扩展的时候无法申请到足够的内存。
- 需要注意的是,栈可以动态扩展,但是栈中的局部变量表不可以。
- StackOverFlowError:线程请求的栈深度大于虚拟机所允许的深度。
2.4、PC寄存器(程序计数器)
- 概念:当前线程所执行的字节码的行号指示器,用于字节码解释器对字节码指令的执行。
- 多线程:通过线程轮流切换并分配处理器执行时间的方式来实现的,在任何一个时刻,一个处理器(也就是一个核)只能执行一条线程中的指令,为了线程切换后能恢复到正确的执行位置,每条线程都要有一个独立的程序计数器,各条线程之间计数器互不影响,独立存储。
0 0
- JVM内存结构分析
- JVM内存结构
- JVM内存结构
- JVM内存结构
- JVM内存结构浅析
- JVM内存结构
- JVM内存结构
- JVM内存结构
- JVM 内存结构
- JVM 内存结构
- jvm内存结构(译)
- jvm的内存结构
- jvm内存结构
- JVM内存逻辑结构
- JVM内存结构
- JVM内存结构浅析
- JVM 内存结构
- JVM内存结构
- Fork/Join框架介绍 I
- PHP htmlspecialchars和htmlspecialchars_decode(函数)
- 细说ReactiveCocoa的冷信号与热信号(二):为什么要区分冷热信号
- 事件手势,手势
- Efficient Graph-Based Image Segmentation
- JVM内存结构
- Java正则表达式语法大全
- 利用backtrace和backtrace_symbols打印函数的调用关系
- 代理模式与动态代理
- .net 泛型简单应用
- .Net网站架构设计(二)Web服务器集群架构
- jquery复选框 选中事件 及其判断是否被选中
- Ubuntu 如何切换到root用户
- Toast 控制显示或关闭(反射实例)