JVM内存及参数解读

概述:
 
        Java虚拟机启动时,会创建堆内存以及方法区
       方法区主要存放虚拟机加载的类信息、常量、静态变量等共享信息。
       当一条线程生成时虚拟机会创建一个虚拟机栈、本地方法栈、计数器、分配给该线程,当该线程执行到一个方法时,会生成一个栈帧,该方法中的局部变量以及参数(基本数据类型和引用类型)会存放在栈帧中,该方法中的对象实例以及数组实例信息会存放在堆内存中
       在进入一个方法会对之前的栈帧进行压栈,将新方法置入栈顶,执行完新方法会根据栈帧中的返回地址找到上一个方法中的执行代码段,进行弹栈操作
       当这个线程执行完成,该栈也对应的会销毁掉
 
 
JVM内存区域分为五个部分,分别是堆,方法区,虚拟机栈,本地方法栈,程序计数器

程序计数器(PC Register)----线程私有

程序计数器是一个记录着当前线程所执行的字节码的行号指示器
 
以便多线程并发处理时,CPU进行上下文切换后告知CPU已完成的日志,避免重复操作
 

虚拟机栈----线程私有

虚拟机栈是位于虚拟机内存中的一片内存区域,它是线程私有的
 
它用来存储栈帧,一个栈帧就对应着一个方法
 
栈帧的出栈和入栈对应着方法的结束和调用的开始
 
-Xss是指设定每个线程堆栈大小,在JDK1.5之前栈容量默认是256K,之后的默认大小是1M
  • 栈帧 一个完整的栈帧保存着以下信息:
    • 局部变量表
    • 操作数栈
    • 栈帧信息
  • 局部变量表----Stack
     局部变量表存储着方法的参数和局部变量
 
     这些表项可以是-----基本类型数据和引用数据类型
 
  • 操作数栈
     操作数栈可理解为java虚拟机栈中的一个用于计算的临时数据存储区会将结果进行压栈后弹栈后给局部变量表
 
  • 栈帧信息
     栈帧信息包括:方法本身的入口地址,方法返回地址,调试信息或者其他的附加信息
存在异常:
  • StackOverflowError
  • JVM会为每个线程的虚拟机栈分配一定的内存大小------>     -Xss参数
     
    因此虚拟机栈能够容纳的栈帧数量是有限的,若栈帧不断进栈而不出栈,最终会导致当前线程虚拟机栈的内存空间耗尽,抛出异常.


     
  • OutOfMemoryError(OOM)
  • 如果虚拟机在扩展栈时无法申请到足够的内存,则将抛出OutOfMemmoryError异常

     

本地方法栈(Native Stack)----线程私有

 
和虚拟机栈一样,均具有线程隔离的特点以及都能抛出StackOverflowError和OutOfMemoryError异常
 
本地方法栈服务的对象是JVM执行的native方法,而虚拟机栈服务的是JVM执行的java方法

Java堆(Head) ----线程共享

Java 堆是被所有线程共享的一块内存区域,在虚拟机启动时创建
 
此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存
JVM内存划分为堆内存非堆内存
 
堆内存:
        (1/3)年轻代(Young Generation):
                       |                     
                       |===(8/10)Eden
                       |
                       |===(2/10)Survivor区
                                                |
                                                |===(1/10)FromSpace
                                                |
                                                |===(1/10)ToSpace
                
        (2/3)老年代(Old Generation)
 
非堆内存:
       永久代(Permanent Generation)
堆内存:
存放的是对象,垃圾收集器就是收集这些对象,然后根据GC算法回收
非堆内存:
永久代,也称为方法区,存储程序运行时长期存活的对象,比如类的元数据、方法、常量、属性等
年轻代(New)
年轻代用来存放JVM刚分配的Java对象
年老代(Tenured):
年轻代中经过垃圾回收没有回收掉的对象将被Copy到年老代
永久代(Perm):
永久代存放Class、Method元信息,其大小跟项目的规模、类、方法的量有关,一般设置为128M就足够,设置原则是预留30%的空间
 
 
备注:
 
JDK1.8版本废弃了永久代,替代的是元空间(MetaSpace)
 
元空间与永久代上类似,都是方法区的实现
 
他们最大区别是:元空间并不在JVM中,而是使用本地内存
 
元空间有注意有两个参数:
 
MetaspaceSize:初始化元空间大小,控制发生GC阈值
MaxMetaspaceSize: 限制元空间大小上限,防止异常占用过多物理内存

方法区(Method Area)

方法区也称"永久代"
 
它用于存储虚拟机加载的类信息、常量、静态变量、是各个线程共享的内存区域
 
JDK8之前的HotSpot JVM,存放这些”永久的”的区域叫做“永久代(permanent generation)”
 
永久代是一片连续的堆空间,在JVM启动之前通过在命令行设置参数-XX:MaxPermSize来设定永久代
 
最大可分配的内存空间,默认大小是64M(64位JVM默认是85M)
 
JDK8后,JVM不再有 永久代(PermGen)
 
但类的元数据信息(metadata)还在,只不过不再是存储在连续的堆空间上,而是移动到叫做“Metaspace”的本地内存(Native memory)
方法区或永生代相关设置
 
-XX:PermSize=64MB 最小尺寸,初始分配
-XX:MaxPermSize=256MB 最大允许分配尺寸,按需分配
设置垃圾不回收
-XX:+CMSClassUnloadingEnabled
-XX:+CMSPermGenSweepingEnabled
默认大小
-server选项下默认MaxPermSize为64m
-client选项下默认MaxPermSize为32m

JVM内存参数设置

-Xms——————————设置堆的最小空间大小
 
-Xmx——————————设置堆的最大空间大小
 
-Xmn——————————设置年轻代大小
 
-XX:NewSize——————————设置新生代最小空间大小
 
-XX:MaxNewSize——————————设置新生代最大空间大小
 
-XX:PermSize——————————设置永久代最小空间大小
 
-XX:MaxPermSize——————————设置永久代最大空间大小
 
-Xss——————————设置每个线程的堆栈大小
 
-XX:+UseParallelGC————————选择垃圾收集器为并行收集器
                                                    此配置仅对年轻代有效----即上述配置下,年轻代使用并发收集,而年老代仍旧使用串行收集
 
-XX:ParallelGCThreads=20——————————配置并行收集器的线程数------即:同时多少个线程一起进行垃圾回收
典型JVM参数配置参考:
 
 
java-Xmx3550m-Xms3550m-Xmn2g-Xss128k
-XX:ParallelGCThreads=20
-XX:+UseConcMarkSweepGC
-XX:+UseParNewGC

解析:

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

猜你喜欢

转载自blog.csdn.net/weixin_43562937/article/details/106537146