Java的JVM(Java虚拟机)参数配置

JVM原理

(1)jvm是java的核心和基础,在java编译器和os平台之间的虚拟处理器,可在上面执行字节码程序。

(2)java编译器只要面向jvm,生成jvm能理解的字节码文件。java源文件经编译成字节码程序,通过jvm将每条指令翻译成不同的机器码,通过特定平台运行。

JVM执行程序的过程

  • 加载.class文件
  • 管理并分配内存
  • 执行垃圾收集

JRE(java运行时环境)由JVM构造的java程序的运行环,也是Java程序运行的环境,但是他同时一个操作系统的一个应用程序一个进程,因此他也有他自己的运行的生命周期,也有自己的代码和数据空间。

JVM在整个jdk中处于最底层,负责于操作系统的交互,用来屏蔽操作系统环境,提供一个完整的Java运行环境,因此也就虚拟计算机。

JVM的生命周期

JVM实例对应了一个独立运行的java程序它是进程级别

1) 启动。启动一个Java程序时,一个JVM实例就产生了,任何一个拥有public static void
main(String[] args)函数的class都可以作为JVM实例运行的起点

2) 运行。main()作为该程序初始线程的起点,任何其他线程均由该线程启动。JVM内部有两种线程:守护线程和非守护线程,main()属于非守护线程,守护线程通常由JVM自己使用,java程序也可以表明自己创建的线程是守护线程

3) 消亡。当程序中的所有非守护线程都终止时,JVM才退出;若安全管理器允许,程序也可以使用Runtime类或者System.exit()来退出

JVM执行引擎实例则对应了属于用户运行程序的线程它是线程级别的

JVM运行时数据区

方法区(Method Area)

方法区是所有线程共享的内存区域,它用于存储已被Java虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。

它有个别命叫Non-Heap(非堆)。当方法区无法满足内存分配需求时,抛出OutOfMemoryError异常。

Java堆(Java Heap)

java堆是java虚拟机所管理的内存中最大的一块,是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例。

在Java虚拟机规范中的描述是:所有的对象实例以及数组都要在堆上分配。

java堆是垃圾收集器管理的主要区域,因此也被成为“GC堆”。

从内存回收角度来看java堆可分为:新生代和老生代。

从内存分配的角度看,线程共享的Java堆中可能划分出多个线程私有的分配缓冲区。

无论怎么划分,都与存放内容无关,无论哪个区域,存储的都是对象实例,进一步的划分都是为了更好的回收内存,或者更快的分配内存。

根据Java虚拟机规范的规定,java堆可以处于物理上不连续的内存空间中。当前主流的虚拟机都是可扩展的(通过 -Xmx 和 -Xms 控制)。如果堆中没有内存可以完成实例分配,并且堆也无法再扩展时,将会抛出OutOfMemoryError异常。

程序计数器(Program Counter Register)

程序计数器是一块较小的内存空间,它可以看作是:保存当前线程所正在执行的字节码指令的地址(行号),也可以把它叫做线程计数器。

由于Java虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的,一个处理器都只会执行一条线程中的指令。因此,为了线程切换后能恢复到正确的执行位置,每条线程都有一个独立的程序计数器,各个线程之间计数器互不影响,独立存储。称之为“线程私有”的内存。程序计数器内存区域是虚拟机中唯一没有规定OutOfMemoryError情况的区域。

Java虚拟机栈(Java Virtual Machine Stacks)

java虚拟机是线程私有的,它的生命周期和线程相同。

虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。

虚拟机栈中是有单位的,单位就是栈帧,一个方法一个栈帧。一个栈帧中他又要存储,局部变量,操作数栈,动态链接,出口等。

本地方法栈(Native Method Stack)

本地方法栈很好理解,他很栈很像,只不过方法上带了 native 关键字的栈字

它是虚拟机栈为虚拟机执行Java方法(也就是字节码)的服务

native关键字的方法是看不到的,必须要去oracle官网去下载才可以看的到,而且native关键字修饰的大部分源码都是C和C++的代码。

同理可得,本地方法栈中就是C和C++的代码

Java内存结构

直接内存(Direct Memory)

直接内存不是虚拟机运行时数据区的一部分,也不是java虚拟机规范中定义的内存区域。但是既然是内存,肯定还是受本机总内存(包括RAM以及SWAP区或者分页文件)大小以及处理器寻址空间的限制。

在JDK1.4 中新加入了NIO(New Input/Output)类,引入了一种基于通道(Channel)与缓冲区(Buffer)的I/O 方式,它可以使用native 函数库直接分配堆外内存,然后通脱一个存储在Java堆中的DirectByteBuffer 对象作为这块内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免了在Java堆和Native(本地)堆中来回复制数据。

直接内存与堆内存的区别:

直接内存申请空间耗费很高的性能,堆内存申请空间耗费比较低

直接内存的IO读写的性能要优于堆内存,在多次读写操作的情况相差非常明显

JVM字节码执行引擎

虚拟机核心的组件就是执行引擎,它负责执行虚拟机的字节码,一般户先进行编译成机器码后执行。

“虚拟机”是一个相对于“物理机”的概念,虚拟机的字节码是不能直接在物理机上运行的,需要JVM字节码执行引擎编译成机器码后才可在物理机上执行。

垃圾收集系统

程序在运行过程中,会产生大量的内存垃圾(一些没有引用指向的内存对象都属于内存垃圾,因为这些对象已经无法访问,程序用不了它们了,对程序而言它们已经死亡),为了确保程序运行时的性能,java虚拟机在程序运行的过程中不断地进行自动的垃圾回收(GC)。

垃圾收集系统是Java的核心,也是不可少的,Java有一套自己进行垃圾清理的机制,开发人员无需手工清理。

JVM的垃圾回收机制

垃圾回收机制简称GC

GC主要用于Java堆的管理。Java 中的堆是 JVM 所管理的最大的一块内存空间,主要用于存放各种类的实例对象。

什么是垃圾回收机制

程序在运行过程中,会产生大量的内存垃圾(一些没有引用指向的内存对象都属于内存垃圾,因为这些对象已经无法访问,程序用不了它们了,对程序而言它们已经死亡),为了确保程序运行时的性能,java虚拟机在程序运行的过程中不断地进行自动的垃圾回收(GC)。

GC是不定时去堆内存中清理不可达对象。不可达的对象并不会马上就会直接回收, 垃圾收集器在一个Java程序中的执行是自动的,不能强制执行清楚那个对象,即使程序员能明确地判断出有一块内存已经无用了,是应该回收的,程序员也不能强制垃圾收集器回收该内存块。程序员唯一能做的就是通过调用System.gc 方法来"建议"执行垃圾收集器,但是他是否执行,什么时候执行却都是不可知的。这也是垃圾收集器的最主要的缺点。当然相对于它给程序员带来的巨大方便性而言,这个缺点是瑕不掩瑜的。

手动执行GC:

System.gc(); // 手动回收垃圾

finalize方法作用

finalize()方法是在每次执行GC操作之前时会调用的方法,可以用它做必要的清理工作。
它是在Object类中定义的,因此所有的类都继承了它。子类覆盖finalize()方法以整理系统资源或者执行其他清理工作。finalize()方法是在垃圾收集器删除对象之前对这个对象调用的。

public class Test {
	public static void main(String[] args) {
		Test test = new Test();
		test = null;
		System.gc(); // 手动回收垃圾
	}

	@Override
	protected void finalize() throws Throwable {
		// gc回收垃圾之前调用
		System.out.println("gc回收垃圾之前调用的方法");
	}
}

新生代、老年代、永久代(方法区)的区别

Java 中的堆是 JVM 所管理的最大的一块内存空间,主要用于存放各种类的实例对象。

在 Java 中,堆被划分成两个不同的区域:新生代 ( Young )、老年代 ( Old )。

老年代就一个区域。新生代 ( Young ) 又被划分为三个区域:Eden、From Survivor、To Survivor。

这样划分的目的是为了使 JVM 能够更好的管理堆内存中的对象,包括内存的分配以及回收。

默认的,新生代 ( Young ) 与老年代 ( Old ) 的比例的值为 1:2 ( 该值可以通过参数 –XX:NewRatio 来指定 ),即:新生代 ( Young ) = 1/3 的堆空间大小。老年代 ( Old ) = 2/3 的堆空间大小。

其中,新生代 ( Young ) 被细分为 Eden 和 两个 Survivor 区域,这两个 Survivor 区域分别被命名为 From Survivor 和 ToSurvivor ,以示区分。

默认的,Edem : From Survivor : To Survivor = 8 : 1 : 1 ( 可以通过参数 –XX:SurvivorRatio 来设定 ),即: Eden = 8/10 的新生代空间大小,From Survivor = To Survivor = 1/10 的新生代空间大小。

JVM 每次只会使用 Eden 和其中的一块 Survivor 区域来为对象服务,所以无论什么时候,总是有一块 Survivor 区域是空闲着的。

因此,新生代实际可用的内存空间为 9/10 ( 即90% )的新生代空间。

永久代就是JVM的方法区。在这里都是放着一些被虚拟机加载的类信息,静态变量,常量等数据。这个区中的东西比老年代和新生代更不容易回收。

Minor GC、Major GC、Full GC区别及触发条件

Minor GC是新生代GC,指的是发生在新生代的垃圾收集动作。由于java对象大都是朝生夕死的,所以Minor GC非常频繁,一般回收速度也比较快。

Major GC是老年代GC,指的是发生在老年代的GC,通常执行Major GC会连着Minor GC一起执行。Major GC的速度要比Minor GC慢的多。

Full GC是清理整个堆空间,包括年轻代和老年代

Minor GC 触发条件一般为:

  • eden区满时,触发MinorGC。即申请一个对象时,发现eden区不够用,则触发一次MinorGC。
  • 新创建的对象大小 > Eden所剩空间

Major GC和Full GC 触发条件一般为:

Major GC通常是跟full GC是等价的

  • 每次晋升到老年代的对象平均大小>老年代剩余空间
  • MinorGC后存活的对象超过了老年代剩余空间
  • 永久代空间不足
  • 执行System.gc()
  • CMS GC异常
  • 堆内存分配很大的对象

垃圾收集器

垃圾收集器是垃圾回收算法(引用计数法、标记清楚法、标记整理法、复制算法)的具体实现,不同垃圾收集器、不同版本的JVM所提供的垃圾收集器可能会有很在差别。

  • 新生代收集器:Serial、ParNew、Parallel Scavenge
  • 老年代收集器:CMS、Serial Old、Parallel Old
  • 整堆收集器:G1

垃圾回收器详解

垃圾回收器工作区域回收算法工作线程用户线程并行描述
Serial新生带复制算法单线程Client模式下默认新生代收集器。简单高效
ParNew新生带复制算法多线程Serial的多线程版本,Server模式下首选, 可搭配CMS的新生代收集器
Parallel Scavenge新生带复制算法多线程目标是达到可控制的吞吐量
Serial Old老年带标记-整理单线程Serial老年代版本,给Client模式下的虚拟机使用
Parallel Old老年带标记-整理多线程Parallel Scavenge老年代版本,吞吐量优先
CMS老年带标记-清楚多线程追求最短回收停顿时间
G1新生带 + 老年带标记-整理 + 复制算法多线程JDK1.9默认垃圾收集器

JVM参数配置

-Xms:初始堆大小,JVM 启动的时候,给定堆空间大小。 

-Xmx:最大堆大小,JVM 运行过程中,如果初始堆空间不足的时候,最大可以扩展到多少。 

-Xmn:设置堆中年轻代大小。整个堆大小=年轻代大小+年老代大小+持久代大小。 

-XX:NewSize=n 设置年轻代初始化大小大小 

-XX:MaxNewSize=n 设置年轻代最大值

-XX:NewRatio=n 设置年轻代和年老代的比值。如: -XX:NewRatio=3,表示年轻代与年老代比值为 1:3,年轻代占整个年轻代+年老代和的 1/4 

-XX:SurvivorRatio=n 年轻代中 Eden 区与两个 Survivor 区的比值。注意 Survivor 区有两个。8表示两个Survivor :eden=2:8 ,即一个Survivor占年轻代的1/10,默认就为8

-Xss:设置每个线程的堆栈大小。JDK5后每个线程 Java 栈大小为 1M,以前每个线程堆栈大小为 256K。

-XX:ThreadStackSize=n 线程堆栈大小

-XX:PermSize=n 设置持久代初始值	

-XX:MaxPermSize=n 设置持久代大小
 
-XX:MaxTenuringThreshold=n 设置年轻带垃圾对象最大年龄。如果设置为 0 的话,则年轻代对象不经过 Survivor 区,直接进入年老代。


-XX:LargePageSizeInBytes=n 设置堆内存的内存页大小

-XX:+UseFastAccessorMethods 优化原始类型的getter方法性能

-XX:+DisableExplicitGC 禁止在运行期显式地调用System.gc(),默认启用	

-XX:+AggressiveOpts 是否启用JVM开发团队最新的调优成果。例如编译优化,偏向锁,并行年老代收集等,jdk6纸之后默认启动

-XX:+UseBiasedLocking 是否启用偏向锁,JDK6默认启用	

-Xnoclassgc 是否禁用垃圾回收

-XX:+UseThreadPriorities 使用本地线程的优先级,默认启用

JVM的GC垃圾收集器设置

-XX:+UseSerialGC:设置串行收集器,年轻带收集器 

-XX:+UseParNewGC:设置年轻代为并行收集。可与 CMS 收集同时使用。JDK5.0 以上,JVM 会根据系统配置自行设置,所以无需再设置此值。

-XX:+UseParallelGC:设置并行收集器,目标是目标是达到可控制的吞吐量

-XX:+UseParallelOldGC:设置并行年老代收集器,JDK6.0 支持对年老代并行收集。 

-XX:+UseConcMarkSweepGC:设置年老代并发收集器

-XX:+UseG1GC:设置 G1 收集器,JDK1.9默认垃圾收集器

示例:

假设服务器内存8G,运行8个微服务,给每个微服务分配800M内存

设置JVM:

java -Xmx800m -Xms800m -Xmn300m -Xss1024k

-Xmx800m 设置JVM最大内存为800M
-Xms800m 设置JVM最小内存为800M(与最大值保持一致可以防止每次垃圾回收(GC)后JVM对内存进行再分配)
-Xmn300m 设置新生代大小,新生代大小会影响到老年代的大小,Sun推荐设置为总内存的3/8
-Xss1024k 每个线程堆栈大小,值越小能生成的线程数越多,但是一般不超过5000个,在递归场景下值太小可能会造成堆栈溢出

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Java虚拟机的内存配置参数有:Xms,Xmx,MaxPermSize和MetaspaceSize。Xms表示Java虚拟机启动时分配的内存容量;Xmx表示Java虚拟机最大可分配的内存容量;MaxPermSize表示持久代(永久代)的最大可分配的内存容量;MetaspaceSize表示元空间的最大可分配的内存容量。 ### 回答2: Java 虚拟机的内存配置参数有以下几个: 1. -Xms:代表初始堆内存大小,用于指定 Java 堆内存的初始大小。例如,-Xms512m 表示堆内存初始大小为 512MB。 2. -Xmx:代表最大堆内存大小,用于指定 Java 堆内存的最大可用大小。例如,-Xmx1024m 表示堆内存最大可用大小为 1GB。 3. -Xss:代表线程堆栈大小,用于指定每个线程的堆栈大小。例如,-Xss256k 表示每个线程的堆栈大小为 256KB。 4. -Xmn:代表新生代堆内存大小,用于指定 Java 堆内存中新生代的大小。例如,-Xmn256m 表示新生代堆内存大小为 256MB。 5. -XX:MetaspaceSize:代表元空间大小,用于指定元空间(原永久代)的初始大小。例如,-XX:MetaspaceSize=128m 表示元空间初始大小为 128MB。 通过这些内存配置参数,我们可以根据应用程序的需求合理地分配内存空间。-Xms 和 -Xmx 可以控制堆内存的初始大小和最大可用大小,避免内存空间过大或过小导致性能问题。-Xss 可以控制线程的堆栈大小,避免线程数量过多导致内存溢出。-Xmn 可以控制新生代堆内存的大小,优化垃圾回收的效率。-XX:MetaspaceSize 可以控制元空间的初始大小,避免元数据占用过多内存。 合理配置这些内存参数可以提高 Java 程序的性能和稳定性,确保应用程序可以正常运行并充分利用系统资源。 ### 回答3: Java虚拟机的内存配置参数有以下几个: 1. -Xms: 该参数用于指定Java虚拟机的初始堆大小。默认值通常为物理内存的1/64。例如,-Xms512m表示初始堆大小为512MB。 2. -Xmx: 该参数用于指定Java虚拟机的最大堆大小。默认值通常为物理内存的1/4。例如,-Xmx2g表示最大堆大小为2GB。 3. -Xmn: 该参数用于指定Java虚拟机的年轻代大小。年轻代是堆的一部分,用于存储新创建的对象。默认值通常为整个堆大小的1/3或1/4。例如,-Xmn256m表示年轻代大小为256MB。 4. -XX:MaxPermSize: 该参数用于指定Java虚拟机的永久代大小。永久代用于存储类信息、常量池等。在Java 8及更高版本中,永久代被元空间(Metaspace)取代。例如,-XX:MaxPermSize128m表示永久代大小为128MB。 5. -Xss: 该参数用于指定Java虚拟机的每个线程的默认栈大小。默认值通常为1MB。栈用于存储线程的方法调用和局部变量等。例如,-Xss256k表示栈大小为256KB。 以上是Java虚拟机的主要内存配置参数,通过调整这些参数,可以根据应用程序的需求来优化内存的使用。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值